From 111f37fbd3d90a6421e7e69b55f4f5574d0bedd4 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 26 Nov 2024 19:41:55 +0000 Subject: [PATCH 01/55] feat: Support metadata on Object node schema --- .../dds/tree/api-report/tree.alpha.api.md | 34 +++++++++----- packages/dds/tree/api-report/tree.beta.api.md | 34 +++++++++----- .../tree/api-report/tree.legacy.alpha.api.md | 34 +++++++++----- .../tree/api-report/tree.legacy.public.api.md | 34 +++++++++----- .../dds/tree/api-report/tree.public.api.md | 34 +++++++++----- packages/dds/tree/src/index.ts | 2 + .../tree/src/simple-tree/api/schemaFactory.ts | 18 ++++++-- .../dds/tree/src/simple-tree/arrayNode.ts | 4 ++ .../src/simple-tree/core/treeNodeSchema.ts | 44 ++++++++++++++++--- packages/dds/tree/src/simple-tree/index.ts | 2 + .../tree/src/simple-tree/leafNodeSchema.ts | 2 + packages/dds/tree/src/simple-tree/mapNode.ts | 4 ++ .../dds/tree/src/simple-tree/objectNode.ts | 10 ++++- .../tree/src/simple-tree/objectNodeTypes.ts | 25 ++++++----- .../dds/tree/src/simple-tree/schemaTypes.ts | 42 ++++++++++++++++++ .../simple-tree/api/schemaFactory.spec.ts | 17 ++++++- .../src/test/simple-tree/core/types.spec.ts | 4 ++ .../api-report/fluid-framework.alpha.api.md | 34 +++++++++----- .../api-report/fluid-framework.beta.api.md | 34 +++++++++----- .../fluid-framework.legacy.alpha.api.md | 34 +++++++++----- .../fluid-framework.legacy.public.api.md | 34 +++++++++----- .../api-report/fluid-framework.public.api.md | 34 +++++++++----- 22 files changed, 380 insertions(+), 134 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 128b3b3bb851..561c6122d777 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -476,6 +476,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @alpha export const noopValidator: JsonValidator; @@ -602,8 +613,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -615,16 +626,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @alpha @@ -834,10 +845,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -850,7 +861,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -859,10 +870,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index 34f2e4f70fd0..328267a120ce 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -266,6 +266,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -364,8 +375,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -377,16 +388,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @public @@ -505,10 +516,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -521,7 +532,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -530,10 +541,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index c4a4c68bb46a..d5e3e54ca7ab 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -261,6 +261,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -359,8 +370,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -372,16 +383,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @public @@ -492,10 +503,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -508,7 +519,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -517,10 +528,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index c22b34b8452f..39dde7c53a18 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -261,6 +261,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -359,8 +370,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -372,16 +383,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @public @@ -489,10 +500,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -505,7 +516,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -514,10 +525,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index c22b34b8452f..39dde7c53a18 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -261,6 +261,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -359,8 +370,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -372,16 +383,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @public @@ -489,10 +500,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -505,7 +516,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -514,10 +525,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/dds/tree/src/index.ts b/packages/dds/tree/src/index.ts index b9dd6f3a00e7..4cdf0fcd95c6 100644 --- a/packages/dds/tree/src/index.ts +++ b/packages/dds/tree/src/index.ts @@ -175,6 +175,8 @@ export { type TreeBranch, type TreeBranchEvents, asTreeViewAlpha, + type NodeSchemaMetadata, + type NodeSchemaOptions, } from "./simple-tree/index.js"; export { SharedTree, diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 8a8efaf86628..f962196bf4b1 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -37,6 +37,8 @@ import { createFieldSchema, type DefaultProvider, getDefaultProvider, + type NodeSchemaMetadata, + type NodeSchemaOptions, } from "../schemaTypes.js"; import { inPrototypeChain } from "../core/index.js"; import type { @@ -322,18 +324,22 @@ export class SchemaFactory< public object< const Name extends TName, const T extends RestrictiveStringRecord, + const TMetadata extends NodeSchemaMetadata, >( name: Name, fields: T, + options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, - T + T, + never, + TMetadata > { - return objectSchema(this.scoped(name), fields, true); + return objectSchema(this.scoped(name), fields, true, options); } /** @@ -730,18 +736,22 @@ export class SchemaFactory< public objectRecursive< const Name extends TName, const T extends Unenforced>, - >(name: Name, t: T) { + const TMetadata extends NodeSchemaMetadata, + >(name: Name, t: T, options?: NodeSchemaOptions) { type TScopedName = ScopedSchemaName; return this.object( name, t as T & RestrictiveStringRecord, + options, ) as unknown as TreeNodeSchemaClass< TScopedName, NodeKind.Object, TreeObjectNodeUnsafe, object & InsertableObjectFromSchemaRecordUnsafe, false, - T + T, + never, + TMetadata >; } diff --git a/packages/dds/tree/src/simple-tree/arrayNode.ts b/packages/dds/tree/src/simple-tree/arrayNode.ts index 01b9e1108732..61a9fa0f3bb2 100644 --- a/packages/dds/tree/src/simple-tree/arrayNode.ts +++ b/packages/dds/tree/src/simple-tree/arrayNode.ts @@ -18,6 +18,7 @@ import { normalizeAllowedTypes, type ImplicitAllowedTypes, type InsertableTreeNodeFromImplicitAllowedTypes, + type NodeSchemaMetadata, type TreeLeafValue, type TreeNodeFromImplicitAllowedTypes, } from "./schemaTypes.js"; @@ -1157,6 +1158,9 @@ export function arraySchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } + public static get metadata(): NodeSchemaMetadata | undefined { + return undefined; // TODO + } // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts b/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts index 6d84f146c63b..eda50204ab0a 100644 --- a/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts +++ b/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import type { TreeLeafValue } from "../schemaTypes.js"; +import type { NodeSchemaMetadata, TreeLeafValue } from "../schemaTypes.js"; import type { InternalTreeNode, TreeNode, Unhydrated } from "./types.js"; /** @@ -27,11 +27,30 @@ export type TreeNodeSchema< TBuild = never, ImplicitlyConstructable extends boolean = boolean, Info = unknown, + TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, > = | (TNode extends TreeNode - ? TreeNodeSchemaClass + ? TreeNodeSchemaClass< + Name, + Kind, + TNode, + TBuild, + ImplicitlyConstructable, + Info, + never, + TMetadata + > : never) - | TreeNodeSchemaNonClass; + | TreeNodeSchemaNonClass< + Name, + Kind, + TNode, + TBuild, + ImplicitlyConstructable, + Info, + never, + TMetadata + >; /** * Schema which is not a class. @@ -49,7 +68,8 @@ export type TreeNodeSchemaNonClass< ImplicitlyConstructable extends boolean = boolean, Info = unknown, TConstructorExtra = never, -> = TreeNodeSchemaCore & + TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, +> = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { /** @@ -119,7 +139,8 @@ export type TreeNodeSchemaClass< ImplicitlyConstructable extends boolean = boolean, Info = unknown, TConstructorExtra = never, -> = TreeNodeSchemaCore & + TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, +> = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { /** @@ -157,6 +178,7 @@ export type TreeNodeSchemaBoth< ImplicitlyConstructable extends boolean = boolean, Info = unknown, TConstructorExtra = never, + TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, > = TreeNodeSchemaClass< Name, Kind, @@ -164,7 +186,8 @@ export type TreeNodeSchemaBoth< TInsertable, ImplicitlyConstructable, Info, - TConstructorExtra + TConstructorExtra, + TMetadata > & TreeNodeSchemaNonClass< Name, @@ -173,7 +196,8 @@ export type TreeNodeSchemaBoth< TInsertable, ImplicitlyConstructable, Info, - TConstructorExtra + TConstructorExtra, + TMetadata >; /** @@ -188,6 +212,7 @@ export interface TreeNodeSchemaCore< out ImplicitlyConstructable extends boolean, out Info = unknown, out TInsertable = never, + out TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, > { /** * Unique (within a document's schema) identifier used to associate nodes with their schema. @@ -244,6 +269,11 @@ export interface TreeNodeSchemaCore< */ readonly childTypes: ReadonlySet; + /** + * User-provided {@link NodeSchemaMetadata} for this schema. + */ + readonly metadata?: TMetadata | undefined; + /** * Constructs an instance of this node type. * @remarks diff --git a/packages/dds/tree/src/simple-tree/index.ts b/packages/dds/tree/src/simple-tree/index.ts index 708def9ac6bd..7b83fa9acd29 100644 --- a/packages/dds/tree/src/simple-tree/index.ts +++ b/packages/dds/tree/src/simple-tree/index.ts @@ -154,6 +154,8 @@ export { type Input, type ReadableField, type ReadSchema, + type NodeSchemaMetadata, + type NodeSchemaOptions, } from "./schemaTypes.js"; export { getTreeNodeForField, diff --git a/packages/dds/tree/src/simple-tree/leafNodeSchema.ts b/packages/dds/tree/src/simple-tree/leafNodeSchema.ts index 5612de18c0f6..bb885c3a8c03 100644 --- a/packages/dds/tree/src/simple-tree/leafNodeSchema.ts +++ b/packages/dds/tree/src/simple-tree/leafNodeSchema.ts @@ -12,6 +12,7 @@ import { valueSchemaAllows, } from "../feature-libraries/index.js"; import { NodeKind, type TreeNodeSchema, type TreeNodeSchemaNonClass } from "./core/index.js"; +import type { NodeSchemaMetadata } from "./schemaTypes.js"; /** * Instances of this class are schema for leaf nodes. @@ -30,6 +31,7 @@ export class LeafNodeSchema public readonly info: T; public readonly implicitlyConstructable = true as const; public readonly childTypes: ReadonlySet = new Set(); + public readonly metadata: NodeSchemaMetadata | undefined = undefined; // TODO public create(data: TreeValue | FlexTreeNode): TreeValue { if (isFlexTreeNode(data)) { diff --git a/packages/dds/tree/src/simple-tree/mapNode.ts b/packages/dds/tree/src/simple-tree/mapNode.ts index f43a0c15a9a9..abfac0fc62f8 100644 --- a/packages/dds/tree/src/simple-tree/mapNode.ts +++ b/packages/dds/tree/src/simple-tree/mapNode.ts @@ -17,6 +17,7 @@ import { normalizeAllowedTypes, type ImplicitAllowedTypes, type InsertableTreeNodeFromImplicitAllowedTypes, + type NodeSchemaMetadata, type TreeNodeFromImplicitAllowedTypes, } from "./schemaTypes.js"; import { @@ -283,6 +284,9 @@ export function mapSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } + public static get metadata(): NodeSchemaMetadata | undefined { + return undefined; // TODO + } // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/simple-tree/objectNode.ts b/packages/dds/tree/src/simple-tree/objectNode.ts index 5d692dc6d13a..f736d316167c 100644 --- a/packages/dds/tree/src/simple-tree/objectNode.ts +++ b/packages/dds/tree/src/simple-tree/objectNode.ts @@ -26,6 +26,8 @@ import { normalizeFieldSchema, type ImplicitAllowedTypes, FieldKind, + type NodeSchemaOptions, + type NodeSchemaMetadata, } from "./schemaTypes.js"; import { type TreeNodeSchema, @@ -326,11 +328,14 @@ export function objectSchema< TName extends string, const T extends RestrictiveStringRecord, const ImplicitlyConstructable extends boolean, + const TMetadata extends NodeSchemaMetadata, >( identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, -): ObjectNodeSchema & ObjectNodeSchemaInternalData { + options?: NodeSchemaOptions, +): ObjectNodeSchema & + ObjectNodeSchemaInternalData { // Ensure no collisions between final set of property keys, and final set of stored keys (including those // implicitly derived from property keys) assertUniqueKeys(identifier, info); @@ -454,6 +459,9 @@ export function objectSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } + public static get metadata(): TMetadata | undefined { + return options?.metadata; + } // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/simple-tree/objectNodeTypes.ts b/packages/dds/tree/src/simple-tree/objectNodeTypes.ts index 58743b6f1bf7..10cc93c6a10e 100644 --- a/packages/dds/tree/src/simple-tree/objectNodeTypes.ts +++ b/packages/dds/tree/src/simple-tree/objectNodeTypes.ts @@ -9,7 +9,7 @@ import type { InsertableObjectFromSchemaRecord, SimpleKeyMap, } from "./objectNode.js"; -import type { ImplicitFieldSchema, FieldSchema } from "./schemaTypes.js"; +import type { ImplicitFieldSchema, FieldSchema, NodeSchemaMetadata } from "./schemaTypes.js"; import { NodeKind, type TreeNodeSchemaClass, type TreeNodeSchema } from "./core/index.js"; import type { FieldKey } from "../core/index.js"; @@ -18,24 +18,27 @@ import type { FieldKey } from "../core/index.js"; * @privateRemarks * This is a candidate for being promoted to the public package API. */ -export interface ObjectNodeSchema< +export type ObjectNodeSchema< TName extends string = string, T extends RestrictiveStringRecord = RestrictiveStringRecord, ImplicitlyConstructable extends boolean = boolean, -> extends TreeNodeSchemaClass< - TName, - NodeKind.Object, - TreeObjectNode, - object & InsertableObjectFromSchemaRecord, - ImplicitlyConstructable, - T - > { + TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, +> = TreeNodeSchemaClass< + TName, + NodeKind.Object, + TreeObjectNode, + object & InsertableObjectFromSchemaRecord, + ImplicitlyConstructable, + T, + never, + TMetadata +> & { /** * From property keys to the associated schema. */ readonly fields: ReadonlyMap; -} +}; /** * Extra data provided on all {@link ObjectNodeSchema} that is not included in the (soon possibly public) ObjectNodeSchema type. diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index fd64bab4ba35..15e2930014db 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -824,3 +824,45 @@ export type NodeBuilderData { + /** + * Optional metadata to associate with the Node Schema. + * @remarks Note: this metadata is not persisted in the document. + */ + readonly metadata?: TMetadata; +} + +/** + * Metadata associated with a Node Schema. + * + * @remarks Specified via {@link NodeSchemaOptions.metadata}. + * + * @sealed + * @public + */ +export interface NodeSchemaMetadata { + /** + * User-defined metadata. + */ + readonly custom?: TCustomMetadata; + + /** + * The description of the Node Schema. + * + * @remarks + * + * If provided, will be used by the system in scenarios where a description of the field is useful. + * E.g., when converting a Node Schema to {@link https://json-schema.org/ | JSON Schema}, this description will be + * used as the `description` property. + */ + readonly description?: string | undefined; +} diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 2753e2415001..d81e8cd92db6 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -363,7 +363,22 @@ describe("schemaFactory", () => { ); }); - it("Field Metadata", () => { + it("Node schema metadata", () => { + const factory = new SchemaFactory(""); + + class Foo extends factory.object( + "Foo", + { bar: factory.number }, + { metadata: { description: "An object", custom: { baz: true } } }, + ) {} + + assert.deepEqual(Foo.metadata, { + description: "An object", + custom: { baz: true }, + }); + }); + + it("Field schema metadata", () => { const schemaFactory = new SchemaFactory("com.example"); const barMetadata = { description: "Bar", diff --git a/packages/dds/tree/src/test/simple-tree/core/types.spec.ts b/packages/dds/tree/src/test/simple-tree/core/types.spec.ts index 0ecfc646aaf3..18b9a72cdb43 100644 --- a/packages/dds/tree/src/test/simple-tree/core/types.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/core/types.spec.ts @@ -24,6 +24,7 @@ import { typeSchemaSymbol, // Used to test that TreeNode is a type only export. TreeNode as TreeNodePublic, + type NodeSchemaMetadata, } from "../../../simple-tree/index.js"; import type { FlexTreeNode } from "../../../feature-libraries/index.js"; // eslint-disable-next-line import/no-internal-modules @@ -135,6 +136,7 @@ describe("simple-tree types", () => { public static readonly identifier = "Subclass"; public static readonly info = numberSchema; public static readonly implicitlyConstructable: false; + public static readonly metadata: NodeSchemaMetadata | undefined = undefined; public static override prepareInstance( this: typeof TreeNodeValid, @@ -235,6 +237,7 @@ describe("simple-tree types", () => { public static readonly info = numberSchema; public static readonly implicitlyConstructable: false; public static readonly childTypes: ReadonlySet = new Set(); + public static readonly metadata: NodeSchemaMetadata | undefined = undefined; public static override buildRawNode( this: typeof TreeNodeValid, @@ -288,6 +291,7 @@ describe("simple-tree types", () => { public static readonly info = numberSchema; public static readonly implicitlyConstructable: false; public static readonly childTypes: ReadonlySet = new Set(); + public static readonly metadata: NodeSchemaMetadata | undefined = undefined; public static override buildRawNode( this: typeof TreeNodeValid, diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 752b27794015..3e2087ce0da1 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -832,6 +832,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @alpha export const noopValidator: JsonValidator; @@ -964,8 +975,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -977,16 +988,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @alpha @@ -1218,10 +1229,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -1234,7 +1245,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -1243,10 +1254,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index 97d42ecbefe5..2e2fdbfd763f 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -619,6 +619,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -723,8 +734,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -736,16 +747,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @public @@ -886,10 +897,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -902,7 +913,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -911,10 +922,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index b19a296b2dd9..dfed03e02116 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -917,6 +917,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -1021,8 +1032,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -1034,16 +1045,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @public @@ -1251,10 +1262,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -1267,7 +1278,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -1276,10 +1287,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index b6be5f6f1a25..7ab9c0872d17 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -650,6 +650,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -754,8 +765,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -767,16 +778,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @public @@ -910,10 +921,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -926,7 +937,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -935,10 +946,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index 39e0f34b993e..2b971baa9380 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -614,6 +614,17 @@ export enum NodeKind { Object = 2 } +// @public @sealed +export interface NodeSchemaMetadata { + readonly custom?: TCustomMetadata; + readonly description?: string | undefined; +} + +// @public +export interface NodeSchemaOptions { + readonly metadata?: TMetadata; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -718,8 +729,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -731,16 +742,16 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; + objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; } // @public @@ -870,10 +881,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -886,7 +897,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -895,10 +906,11 @@ export interface TreeNodeSchemaCore = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; From e611fdda14874f4d5ec16fd39a3f11f26ab32049 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 26 Nov 2024 21:58:42 +0000 Subject: [PATCH 02/55] feat: Add metadata support to map node schema --- .../dds/tree/api-report/tree.alpha.api.md | 4 +- packages/dds/tree/api-report/tree.beta.api.md | 4 +- .../tree/api-report/tree.legacy.alpha.api.md | 4 +- .../tree/api-report/tree.legacy.public.api.md | 4 +- .../dds/tree/api-report/tree.public.api.md | 4 +- .../tree/src/simple-tree/api/schemaFactory.ts | 48 ++++++++++++++----- packages/dds/tree/src/simple-tree/mapNode.ts | 9 ++-- .../dds/tree/src/simple-tree/objectNode.ts | 7 +-- .../simple-tree/api/schemaFactory.spec.ts | 13 +++++ .../api-report/fluid-framework.alpha.api.md | 4 +- .../api-report/fluid-framework.beta.api.md | 4 +- .../fluid-framework.legacy.alpha.api.md | 4 +- .../fluid-framework.legacy.public.api.md | 4 +- .../api-report/fluid-framework.public.api.md | 4 +- 14 files changed, 76 insertions(+), 41 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 561c6122d777..8d7c44ca21d7 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -617,8 +617,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index 328267a120ce..5df1a39b6e54 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -379,8 +379,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index d5e3e54ca7ab..ad66bb6f55ea 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -374,8 +374,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index 39dde7c53a18..9369ebcad112 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -374,8 +374,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index 39dde7c53a18..9369ebcad112 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -374,8 +374,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index f962196bf4b1..829d4c246728 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -339,7 +339,7 @@ export class SchemaFactory< never, TMetadata > { - return objectSchema(this.scoped(name), fields, true, options); + return objectSchema(this.scoped(name), fields, true, options?.metadata); } /** @@ -387,9 +387,14 @@ export class SchemaFactory< * class NamedMap extends factory.map("name", factory.number) {} * ``` */ - public map( + public map< + Name extends TName, + const T extends ImplicitAllowedTypes, + const TMetadata extends NodeSchemaMetadata, + >( name: Name, allowedTypes: T, + options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Map, @@ -397,18 +402,22 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined + undefined, + TMetadata >; /** + * {@link SchemaFactory.map} implementation. + * * @privateRemarks * This should return `TreeNodeSchemaBoth`, however TypeScript gives an error if one of the overloads implicitly up-casts the return type of the implementation. * This seems like a TypeScript bug getting variance backwards for overload return types since it's erroring when the relation between the overload * and the implementation is type safe, and forcing an unsafe typing instead. */ - public map( + public map( nameOrAllowedTypes: TName | ((T & TreeNodeSchema) | readonly TreeNodeSchema[]), allowedTypes?: T, + options?: NodeSchemaOptions, ): TreeNodeSchema, MapNodeInsertableData, true, T> { if (allowedTypes === undefined) { const types = nameOrAllowedTypes as (T & TreeNodeSchema) | readonly TreeNodeSchema[]; @@ -422,6 +431,7 @@ export class SchemaFactory< nameOrAllowedTypes as T, false, true, + options?.metadata, ) as TreeNodeSchema, ) as TreeNodeSchemaBoth< string, @@ -430,7 +440,8 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined + undefined, + TMetadata >; } // To actually have type safety, assign to the type this method should return before implicitly upcasting when returning. @@ -441,8 +452,15 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined - > = this.namedMap(nameOrAllowedTypes as TName, allowedTypes, true, true); + undefined, + TMetadata + > = this.namedMap( + nameOrAllowedTypes as TName, + allowedTypes, + true, + true, + options?.metadata, + ); return out; } @@ -455,11 +473,13 @@ export class SchemaFactory< Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, + TMetadata extends NodeSchemaMetadata, >( name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable, + metadata: TMetadata | undefined, ): TreeNodeSchemaBoth< ScopedSchemaName, NodeKind.Map, @@ -467,7 +487,8 @@ export class SchemaFactory< MapNodeInsertableData, ImplicitlyConstructable, T, - undefined + undefined, + TMetadata > { return mapSchema( this.scoped(name), @@ -475,6 +496,7 @@ export class SchemaFactory< implicitlyConstructable, // The current policy is customizable nodes don't get fake prototypes. !customizable, + metadata, ); } @@ -806,10 +828,11 @@ export class SchemaFactory< * See {@link ValidateRecursiveSchema} for additional information about using recursive schema. */ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - public mapRecursive>( - name: Name, - allowedTypes: T, - ) { + public mapRecursive< + Name extends TName, + const T extends Unenforced, + const TMetadata extends NodeSchemaMetadata, + >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { const MapSchema = this.namedMap( name, allowedTypes as T & ImplicitAllowedTypes, @@ -817,6 +840,7 @@ export class SchemaFactory< // Setting this (implicitlyConstructable) to true seems to work ok currently, but not for other node kinds. // Supporting this could be fragile and might break other future changes, so it's being kept as false for now. false, + options?.metadata, ); return MapSchema as TreeNodeSchemaClass< diff --git a/packages/dds/tree/src/simple-tree/mapNode.ts b/packages/dds/tree/src/simple-tree/mapNode.ts index abfac0fc62f8..d51dbabcea2b 100644 --- a/packages/dds/tree/src/simple-tree/mapNode.ts +++ b/packages/dds/tree/src/simple-tree/mapNode.ts @@ -236,11 +236,13 @@ export function mapSchema< TName extends string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, + const TMetadata extends NodeSchemaMetadata, >( identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, useMapPrototype: boolean, + metadata: TMetadata | undefined, ) { const lazyChildTypes = new Lazy(() => normalizeAllowedTypes(info)); @@ -284,9 +286,7 @@ export function mapSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } - public static get metadata(): NodeSchemaMetadata | undefined { - return undefined; // TODO - } + public static readonly metadata = metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { @@ -303,7 +303,8 @@ export function mapSchema< MapNodeInsertableData, ImplicitlyConstructable, T, - undefined + undefined, + TMetadata > = Schema; return schemaErased; } diff --git a/packages/dds/tree/src/simple-tree/objectNode.ts b/packages/dds/tree/src/simple-tree/objectNode.ts index f736d316167c..c477705049da 100644 --- a/packages/dds/tree/src/simple-tree/objectNode.ts +++ b/packages/dds/tree/src/simple-tree/objectNode.ts @@ -26,7 +26,6 @@ import { normalizeFieldSchema, type ImplicitAllowedTypes, FieldKind, - type NodeSchemaOptions, type NodeSchemaMetadata, } from "./schemaTypes.js"; import { @@ -333,7 +332,7 @@ export function objectSchema< identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, - options?: NodeSchemaOptions, + metadata: TMetadata | undefined, ): ObjectNodeSchema & ObjectNodeSchemaInternalData { // Ensure no collisions between final set of property keys, and final set of stored keys (including those @@ -459,9 +458,7 @@ export function objectSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } - public static get metadata(): TMetadata | undefined { - return options?.metadata; - } + public static readonly metadata = metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index d81e8cd92db6..c750dda6828f 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -614,6 +614,19 @@ describe("schemaFactory", () => { class NamedMap extends factory.map("name", factory.number) {} const namedInstance = new NamedMap(new Map([["x", 5]])); }); + + it("Node schema metadata", () => { + const factory = new SchemaFactory(""); + + class Foo extends factory.map("Foo", factory.number, { + metadata: { description: "A map containing numbers", custom: { baz: true } }, + }) {} + + assert.deepEqual(Foo.metadata, { + description: "A map containing numbers", + custom: { baz: true }, + }); + }); }); describe("produces proxies that can be read after insertion for trees of", () => { diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 3e2087ce0da1..6b0fa1dc5670 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -979,8 +979,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index 2e2fdbfd763f..d1659885e285 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -738,8 +738,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index dfed03e02116..d24349b88ce9 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -1036,8 +1036,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index 7ab9c0872d17..20ac4246a617 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -769,8 +769,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index 2b971baa9380..d065f70e8479 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -733,8 +733,8 @@ export class SchemaFactory, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; + mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe From 72e2398f0cf22885ba616f647c2e5efc60c1c245 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:08:13 +0000 Subject: [PATCH 03/55] feat: Add metadata support to array node schema --- .../dds/tree/api-report/tree.alpha.api.md | 8 +-- packages/dds/tree/api-report/tree.beta.api.md | 8 +-- .../tree/api-report/tree.legacy.alpha.api.md | 8 +-- .../tree/api-report/tree.legacy.public.api.md | 8 +-- .../dds/tree/api-report/tree.public.api.md | 8 +-- .../tree/src/simple-tree/api/schemaFactory.ts | 57 +++++++++++++++---- .../dds/tree/src/simple-tree/arrayNode.ts | 9 +-- .../simple-tree/api/schemaFactory.spec.ts | 13 +++++ .../api-report/fluid-framework.alpha.api.md | 8 +-- .../api-report/fluid-framework.beta.api.md | 8 +-- .../fluid-framework.legacy.alpha.api.md | 8 +-- .../fluid-framework.legacy.public.api.md | 8 +-- .../api-report/fluid-framework.public.api.md | 8 +-- 13 files changed, 103 insertions(+), 56 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 8d7c44ca21d7..0ad521b52d7d 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -609,10 +609,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -625,7 +625,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index 5df1a39b6e54..b3bdacdc77d9 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -371,10 +371,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -387,7 +387,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index ad66bb6f55ea..565922da09b4 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -366,10 +366,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -382,7 +382,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index 9369ebcad112..3a803bb36980 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -366,10 +366,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -382,7 +382,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index 9369ebcad112..3a803bb36980 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -366,10 +366,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -382,7 +382,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 829d4c246728..99c54a5f13e8 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -557,9 +557,14 @@ export class SchemaFactory< * * {@label NAMED} */ - public array( + public array< + const Name extends TName, + const T extends ImplicitAllowedTypes, + const TMetadata extends NodeSchemaMetadata, + >( name: Name, allowedTypes: T, + options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Array, @@ -567,16 +572,23 @@ export class SchemaFactory< Iterable>, true, T, - undefined + undefined, + TMetadata >; /** + * {@link SchemaFactory.array} implementation. + * * @privateRemarks * This should return TreeNodeSchemaBoth: see note on "map" implementation for details. */ - public array( + public array< + const T extends ImplicitAllowedTypes, + const TMetadata extends NodeSchemaMetadata, + >( nameOrAllowedTypes: TName | ((T & TreeNodeSchema) | readonly TreeNodeSchema[]), allowedTypes?: T, + options?: NodeSchemaOptions, ): TreeNodeSchema< ScopedSchemaName, NodeKind.Array, @@ -589,7 +601,7 @@ export class SchemaFactory< const types = nameOrAllowedTypes as (T & TreeNodeSchema) | readonly TreeNodeSchema[]; const fullName = structuralName("Array", types); return getOrCreate(this.structuralTypes, fullName, () => - this.namedArray(fullName, nameOrAllowedTypes as T, false, true), + this.namedArray(fullName, nameOrAllowedTypes as T, false, true, options?.metadata), ) as TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Array, @@ -597,7 +609,8 @@ export class SchemaFactory< Iterable>, true, T, - undefined + undefined, + TMetadata >; } const out: TreeNodeSchemaBoth< @@ -607,8 +620,15 @@ export class SchemaFactory< Iterable>, true, T, - undefined - > = this.namedArray(nameOrAllowedTypes as TName, allowedTypes, true, true); + undefined, + TMetadata + > = this.namedArray( + nameOrAllowedTypes as TName, + allowedTypes, + true, + true, + options?.metadata, + ); return out; } @@ -625,11 +645,13 @@ export class SchemaFactory< Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, + const TMetadata extends NodeSchemaMetadata, >( name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable, + metadata: TMetadata | undefined, ): TreeNodeSchemaBoth< ScopedSchemaName, NodeKind.Array, @@ -637,9 +659,16 @@ export class SchemaFactory< Iterable>, ImplicitlyConstructable, T, - undefined + undefined, + TMetadata > { - return arraySchema(this.scoped(name), allowedTypes, implicitlyConstructable, customizable); + return arraySchema( + this.scoped(name), + allowedTypes, + implicitlyConstructable, + customizable, + metadata, + ); } /** @@ -788,12 +817,14 @@ export class SchemaFactory< public arrayRecursive< const Name extends TName, const T extends Unenforced, - >(name: Name, allowedTypes: T) { + const TMetadata extends NodeSchemaMetadata, + >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { const RecursiveArray = this.namedArray( name, allowedTypes as T & ImplicitAllowedTypes, true, false, + options?.metadata, ); return RecursiveArray as TreeNodeSchemaClass< @@ -816,7 +847,8 @@ export class SchemaFactory< }, false, T, - undefined + undefined, + TMetadata >; } @@ -872,7 +904,8 @@ export class SchemaFactory< }, false, T, - undefined + undefined, + TMetadata >; } } diff --git a/packages/dds/tree/src/simple-tree/arrayNode.ts b/packages/dds/tree/src/simple-tree/arrayNode.ts index 61a9fa0f3bb2..3321100a5d59 100644 --- a/packages/dds/tree/src/simple-tree/arrayNode.ts +++ b/packages/dds/tree/src/simple-tree/arrayNode.ts @@ -1063,11 +1063,13 @@ export function arraySchema< TName extends string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, + const TMetadata extends NodeSchemaMetadata, >( identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, customizable: boolean, + metadata: TMetadata | undefined, ) { type Output = TreeNodeSchemaBoth< TName, @@ -1076,7 +1078,8 @@ export function arraySchema< Iterable>, ImplicitlyConstructable, T, - undefined + undefined, + TMetadata >; const lazyChildTypes = new Lazy(() => normalizeAllowedTypes(info)); @@ -1158,9 +1161,7 @@ export function arraySchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } - public static get metadata(): NodeSchemaMetadata | undefined { - return undefined; // TODO - } + public static readonly metadata: TMetadata | undefined = metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index c750dda6828f..6c53c26b7bb8 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -558,6 +558,19 @@ describe("schemaFactory", () => { class NamedList extends factory.array("name", factory.number) {} const namedInstance = new NamedList([5]); }); + + it("Node schema metadata", () => { + const factory = new SchemaFactory(""); + + class Foo extends factory.array("Foo", factory.number, { + metadata: { description: "An array of numbers", custom: { baz: true } }, + }) {} + + assert.deepEqual(Foo.metadata, { + description: "An array of numbers", + custom: { baz: true }, + }); + }); }); describe("Map", () => { diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 6b0fa1dc5670..85e6f639cae9 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -971,10 +971,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -987,7 +987,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index d1659885e285..171a2b180ff6 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -730,10 +730,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -746,7 +746,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index d24349b88ce9..c194c8ea90f2 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -1028,10 +1028,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -1044,7 +1044,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index 20ac4246a617..c18784866a15 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -761,10 +761,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -777,7 +777,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index d065f70e8479..c5fd2b422b89 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -725,10 +725,10 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; + arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; @@ -741,7 +741,7 @@ export class SchemaFactory; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; From cbf1056ce93cd5cc825e625857128f10f0168bc9 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:30:59 +0000 Subject: [PATCH 04/55] test: Recursive schema tests --- .../api/schemaFactoryRecursive.spec.ts | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts index 2ff896ebc044..0cdfdb9a9219 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts @@ -456,6 +456,30 @@ describe("SchemaFactory Recursive methods", () => { assert.equal((tree.a as B).b!.a, 6); } }); + + it("Node schema metadata", () => { + const factory = new SchemaFactory(""); + + class Foo extends factory.objectRecursive( + "Foo", + { bar: () => Bar }, + { metadata: { description: "A recursive object called Foo", custom: { baz: true } } }, + ) {} + class Bar extends factory.objectRecursive( + "Bar", + { foo: () => Foo }, + { metadata: { description: "A recursive object called Bar", custom: { baz: false } } }, + ) {} + + assert.deepEqual(Foo.metadata, { + description: "A recursive object called Foo", + custom: { baz: true }, + }); + assert.deepEqual(Bar.metadata, { + description: "A recursive object called Bar", + custom: { baz: false }, + }); + }); }); describe("ValidateRecursiveSchema", () => { it("Valid cases", () => { @@ -577,6 +601,22 @@ describe("SchemaFactory Recursive methods", () => { assert.deepEqual([...data], []); } }); + + it("Node schema metadata", () => { + const factory = new SchemaFactory(""); + + class Foo extends factory.objectRecursive("Foo", { + fooList: sf.arrayRecursive("FooList", [() => Foo]), + }) {} + class FooList extends factory.arrayRecursive("FooList", [() => Foo], { + metadata: { description: "A recursive list", custom: { baz: true } }, + }) {} + + assert.deepEqual(FooList.metadata, { + description: "A recursive list", + custom: { baz: true }, + }); + }); }); describe("mapRecursive", () => { @@ -624,6 +664,22 @@ describe("SchemaFactory Recursive methods", () => { // @ts-expect-error Implicit construction disabled const fromNestedObject = new MapRecursive({ x: { x: [] } }); }); + + it("Node schema metadata", () => { + const factory = new SchemaFactory(""); + + class Foo extends factory.objectRecursive("Foo", { + fooList: sf.arrayRecursive("FooList", [() => Foo]), + }) {} + class FooList extends factory.mapRecursive("FooList", [() => Foo], { + metadata: { description: "A recursive map", custom: { baz: true } }, + }) {} + + assert.deepEqual(FooList.metadata, { + description: "A recursive map", + custom: { baz: true }, + }); + }); }); it("recursive under non-recursive", () => { From adcf801e7542a596f1a64b395d998cf45014d024 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 26 Nov 2024 23:38:27 +0000 Subject: [PATCH 05/55] feat: Support metadata in simple schema domain, and map "description" to json schema domain --- .changeset/grey-triangles-shout.md | 68 +++++++++++++++++++ .../dds/tree/api-report/tree.alpha.api.md | 1 + .../tree/src/simple-tree/api/jsonSchema.ts | 7 ++ .../tree/src/simple-tree/api/simpleSchema.ts | 7 +- .../api/simpleSchemaToJsonSchema.ts | 54 +++++++++++---- .../api/viewSchemaToSimpleSchema.ts | 30 ++++++-- .../simple-tree/api/getJsonSchema.spec.ts | 42 ++++++++---- 7 files changed, 174 insertions(+), 35 deletions(-) create mode 100644 .changeset/grey-triangles-shout.md diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md new file mode 100644 index 000000000000..bafce6548451 --- /dev/null +++ b/.changeset/grey-triangles-shout.md @@ -0,0 +1,68 @@ +--- +"@fluidframework/tree": minor +--- +--- +section: tree +--- + +Allow associating metadata with Node Schema + +Users of TreeView can now specify metadata when creating Node Schema. +This includes system-understood metadata, i.e., `description`. + +Example: + +```typescript + +class Point extends schemaFactory.object("Point", { + x: schemaFactory.required(schemaFactory.number), + y: schemaFactory.required(schemaFactory.number), +}, +{ + metadata: { description: "A point in 2D space" } +}) {} + +``` + +Functionality like the experimental conversion of Tree Schema to [JSON Schema](https://json-schema.org/) (`getJsonSchema`) leverages such system-understood metadata to generate useful information. +In the case of the `description` property, this is mapped directly to the `description` property supported by JSON Schema. + +Custom, user-defined properties can also be specified. +These properties will not be leveraged by the system by default, but can be used as a handy means of associating common application-specific properties with Field Schema. + +Example: + +An application is implementing search functionality. +By default, the app author wishes for all app content to be potentially indexable by search, unless otherwise specified. +They can leverage schema metadata to decorate types of nodes that should be ignored by search, and leverage that information when walking the tree during a search. + +```typescript + +interface AppMetadata { + /** + * Whether or not the field should be ignored by search. + * @defaultValue `false` + */ + searchIgnore?: boolean; +} + +class Point extends schemaFactory.object("Point", { + x: schemaFactory.required(schemaFactory.number), + y: schemaFactory.required(schemaFactory.number), +}, +{ + metadata: { + description: "A point in 2D space", + custom: { + searchIgnore: true, + } + } +}) {} + +``` + +Search can then be implemented to look for the appropriate metadata, and leverage it to omit the unwanted position data from search. + +**Note:** these changes add a new property to the base type from which all node schema derive. +If you have existing node schema subclasses that include a property of this name, there is a chance for potential conflict here that could be breaking. +If you encounter issues here, consider renaming your property. diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 0ad521b52d7d..3672ed745887 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -394,6 +394,7 @@ export type JsonNodeSchema = JsonLeafNodeSchema | JsonMapNodeSchema | JsonArrayN // @alpha @sealed export interface JsonNodeSchemaBase { + readonly description?: string | undefined; readonly _treeNodeSchemaKind: TNodeKind; readonly type: TJsonSchemaType; } diff --git a/packages/dds/tree/src/simple-tree/api/jsonSchema.ts b/packages/dds/tree/src/simple-tree/api/jsonSchema.ts index 78815e4cbd8f..4b3c6e438448 100644 --- a/packages/dds/tree/src/simple-tree/api/jsonSchema.ts +++ b/packages/dds/tree/src/simple-tree/api/jsonSchema.ts @@ -58,6 +58,13 @@ export interface JsonNodeSchemaBase< * {@inheritDoc JsonSchemaType} */ readonly type: TJsonSchemaType; + + /** + * Description of the node schema. + * @remarks Derived from {@link NodeSchemaMetadata.description}. + * @see {@link https://json-schema.org/draft/2020-12/json-schema-validation#name-title-and-description} + */ + readonly description?: string | undefined; } /** diff --git a/packages/dds/tree/src/simple-tree/api/simpleSchema.ts b/packages/dds/tree/src/simple-tree/api/simpleSchema.ts index e23639e6add2..d44cf4f5088e 100644 --- a/packages/dds/tree/src/simple-tree/api/simpleSchema.ts +++ b/packages/dds/tree/src/simple-tree/api/simpleSchema.ts @@ -5,7 +5,7 @@ import type { ValueSchema } from "../../core/index.js"; import type { NodeKind } from "../core/index.js"; -import type { FieldKind, FieldSchemaMetadata } from "../schemaTypes.js"; +import type { FieldKind, FieldSchemaMetadata, NodeSchemaMetadata } from "../schemaTypes.js"; /** * Base interface for all {@link SimpleNodeSchema} implementations. @@ -20,6 +20,11 @@ export interface SimpleNodeSchemaBase { * @remarks can be used to type-switch between implementations. */ readonly kind: TNodeKind; + + /** + * Node metadata. + */ + readonly metadata?: NodeSchemaMetadata | undefined; } /** diff --git a/packages/dds/tree/src/simple-tree/api/simpleSchemaToJsonSchema.ts b/packages/dds/tree/src/simple-tree/api/simpleSchemaToJsonSchema.ts index 5e2ebb69d576..303ba8ed399c 100644 --- a/packages/dds/tree/src/simple-tree/api/simpleSchemaToJsonSchema.ts +++ b/packages/dds/tree/src/simple-tree/api/simpleSchemaToJsonSchema.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { unreachableCase } from "@fluidframework/core-utils/internal"; +import { oob, unreachableCase } from "@fluidframework/core-utils/internal"; import { UsageError } from "@fluidframework/telemetry-utils/internal"; import { ValueSchema } from "../../core/index.js"; import { getOrCreate, hasSingle, type Mutable } from "../../util/index.js"; @@ -100,11 +100,18 @@ function convertArrayNodeSchema(schema: SimpleArrayNodeSchema): JsonArrayNodeSch ? allowedTypes[0] : { anyOf: allowedTypes }; - return { + const output: Mutable = { type: "array", _treeNodeSchemaKind: NodeKind.Array, items, }; + + // Only include "description" property if it is present in the input. + if (schema.metadata?.description !== undefined) { + output.description = schema.metadata.description; + } + + return output; } function convertLeafNodeSchema(schema: SimpleLeafNodeSchema): JsonLeafNodeSchema { @@ -137,9 +144,9 @@ function convertLeafNodeSchema(schema: SimpleLeafNodeSchema): JsonLeafNodeSchema function convertObjectNodeSchema(schema: SimpleObjectNodeSchema): JsonObjectNodeSchema { const properties: Record = {}; const required: string[] = []; - for (const [key, value] of Object.entries(schema.fields)) { + for (const [key, fieldSchema] of Object.entries(schema.fields)) { const allowedTypes: JsonSchemaRef[] = []; - for (const allowedType of value.allowedTypes) { + for (const allowedType of fieldSchema.allowedTypes) { allowedTypes.push(createSchemaRef(allowedType)); } @@ -149,24 +156,32 @@ function convertObjectNodeSchema(schema: SimpleObjectNodeSchema): JsonObjectNode anyOf: allowedTypes, }; - // Don't include "description" property at all if it's not present in the input. - if (value.metadata?.description !== undefined) { - output.description = value.metadata.description; + // Only include "description" property if it is present in the input. + if (fieldSchema.metadata?.description !== undefined) { + output.description = fieldSchema.metadata.description; } properties[key] = output; - if (value.kind === FieldKind.Required) { + if (fieldSchema.kind === FieldKind.Required) { required.push(key); } } - return { + + const transformedNode: Mutable = { type: "object", _treeNodeSchemaKind: NodeKind.Object, properties, required, additionalProperties: false, }; + + // Only include "description" property if it is present in the input. + if (schema.metadata?.description !== undefined) { + transformedNode.description = schema.metadata.description; + } + + return transformedNode; } function convertMapNodeSchema(schema: SimpleMapNodeSchema): JsonMapNodeSchema { @@ -174,17 +189,26 @@ function convertMapNodeSchema(schema: SimpleMapNodeSchema): JsonMapNodeSchema { schema.allowedTypes.forEach((type) => { allowedTypes.push(createSchemaRef(type)); }); - return { + + const output: Mutable = { type: "object", _treeNodeSchemaKind: NodeKind.Map, patternProperties: { - "^.*$": hasSingle(allowedTypes) - ? allowedTypes[0] - : { - anyOf: allowedTypes, - }, + "^.*$": + allowedTypes.length === 1 + ? (allowedTypes[0] ?? oob()) + : { + anyOf: allowedTypes, + }, }, }; + + // Only include "description" property if it is present in the input. + if (schema.metadata?.description !== undefined) { + output.description = schema.metadata.description; + } + + return output; } function createSchemaRef(schemaId: string): JsonSchemaRef { diff --git a/packages/dds/tree/src/simple-tree/api/viewSchemaToSimpleSchema.ts b/packages/dds/tree/src/simple-tree/api/viewSchemaToSimpleSchema.ts index f356e3d530f7..0d7b9405259e 100644 --- a/packages/dds/tree/src/simple-tree/api/viewSchemaToSimpleSchema.ts +++ b/packages/dds/tree/src/simple-tree/api/viewSchemaToSimpleSchema.ts @@ -41,7 +41,7 @@ export function toSimpleTreeSchema(schema: ImplicitFieldSchema): SimpleTreeSchem definitions, }; - // Include the "description" property only if it's present on the input. + // Include the "metadata" property only if it's present on the input. if (normalizedSchema.metadata !== undefined) { output.metadata = normalizedSchema.metadata; } @@ -95,20 +95,34 @@ function leafSchemaToSimpleSchema(schema: TreeNodeSchema): SimpleLeafNodeSchema function arraySchemaToSimpleSchema(schema: TreeNodeSchema): SimpleArrayNodeSchema { const fieldSchema = normalizeFieldSchema(schema.info as ImplicitAllowedTypes); const allowedTypes = allowedTypesFromFieldSchema(fieldSchema); - return { + const output: Mutable = { kind: NodeKind.Array, allowedTypes, }; + + // Only include "metadata" property if it is present in the input. + if (schema.metadata !== undefined) { + output.metadata = schema.metadata; + } + + return output; } // TODO: Use a stronger type for map schemas once one is available (see object schema handler for an example). function mapSchemaToSimpleSchema(schema: TreeNodeSchema): SimpleMapNodeSchema { const fieldSchema = normalizeFieldSchema(schema.info as ImplicitAllowedTypes); const allowedTypes = allowedTypesFromFieldSchema(fieldSchema); - return { + const output: Mutable = { kind: NodeKind.Map, allowedTypes, }; + + // Only include "metadata" property if it is present in the input. + if (schema.metadata !== undefined) { + output.metadata = schema.metadata; + } + + return output; } function objectSchemaToSimpleSchema(schema: ObjectNodeSchema): SimpleObjectNodeSchema { @@ -116,10 +130,18 @@ function objectSchemaToSimpleSchema(schema: ObjectNodeSchema): SimpleObjectNodeS for (const [key, field] of schema.fields) { fields[key] = fieldSchemaToSimpleSchema(field); } - return { + + const output: Mutable = { kind: NodeKind.Object, fields, }; + + // Only include "metadata" property if it is present in the input. + if (schema.metadata !== undefined) { + output.metadata = schema.metadata; + } + + return output; } /** diff --git a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts index 6b13489ca571..f181a1859b22 100644 --- a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts @@ -126,15 +126,18 @@ describe("getJsonSchema", () => { it("Array schema", () => { const schemaFactory = new SchemaFactory("test"); - const Schema = schemaFactory.array(schemaFactory.string); + const Schema = schemaFactory.array("array", schemaFactory.string, { + metadata: { description: "An array of strings" }, + }); const actual = getJsonSchema(Schema); const expected: JsonTreeSchema = { $defs: { - 'test.Array<["com.fluidframework.leaf.string"]>': { + "test.array": { type: "array", _treeNodeSchemaKind: NodeKind.Array, + description: "An array of strings", items: { $ref: "#/$defs/com.fluidframework.leaf.string", }, @@ -144,7 +147,7 @@ describe("getJsonSchema", () => { _treeNodeSchemaKind: NodeKind.Leaf, }, }, - $ref: '#/$defs/test.Array<["com.fluidframework.leaf.string"]>', + $ref: "#/$defs/test.array", }; assert.deepEqual(actual, expected); @@ -152,7 +155,6 @@ describe("getJsonSchema", () => { const validator = getJsonValidator(actual); // Verify expected data validation behavior. - validator(hydrate(Schema, ["Hello", "world"]), true); validator([], true); validator(["Hello", "world"], true); validator("Hello world", false); @@ -163,14 +165,17 @@ describe("getJsonSchema", () => { it("Map schema", () => { const schemaFactory = new SchemaFactory("test"); - const Schema = schemaFactory.map(schemaFactory.string); + const Schema = schemaFactory.map("map", schemaFactory.string, { + metadata: { description: "A map containing strings" }, + }); const actual = getJsonSchema(Schema); const expected: JsonTreeSchema = { $defs: { - 'test.Map<["com.fluidframework.leaf.string"]>': { + "test.map": { type: "object", _treeNodeSchemaKind: NodeKind.Map, + description: "A map containing strings", patternProperties: { "^.*$": { $ref: "#/$defs/com.fluidframework.leaf.string" }, }, @@ -180,7 +185,7 @@ describe("getJsonSchema", () => { _treeNodeSchemaKind: NodeKind.Leaf, }, }, - $ref: '#/$defs/test.Map<["com.fluidframework.leaf.string"]>', + $ref: "#/$defs/test.map", }; assert.deepEqual(actual, expected); @@ -220,14 +225,20 @@ describe("getJsonSchema", () => { it("Object schema", () => { const schemaFactory = new SchemaFactory("test"); - const Schema = schemaFactory.object("object", { - foo: schemaFactory.optional(schemaFactory.number, { - metadata: { description: "A number representing the concept of Foo." }, - }), - bar: schemaFactory.required(schemaFactory.string, { - metadata: { description: "A string representing the concept of Bar." }, - }), - }); + const Schema = schemaFactory.object( + "object", + { + foo: schemaFactory.optional(schemaFactory.number, { + metadata: { description: "A number representing the concept of Foo." }, + }), + bar: schemaFactory.required(schemaFactory.string, { + metadata: { description: "A string representing the concept of Bar." }, + }), + }, + { + metadata: { description: "An object with Foo and Bar." }, + }, + ); const actual = getJsonSchema(Schema); @@ -236,6 +247,7 @@ describe("getJsonSchema", () => { "test.object": { type: "object", _treeNodeSchemaKind: NodeKind.Object, + description: "An object with Foo and Bar.", properties: { foo: { $ref: "#/$defs/com.fluidframework.leaf.number", From 167f53862b1828efa3eedf3adf34489ded25a70a Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Mon, 2 Dec 2024 19:31:36 +0000 Subject: [PATCH 06/55] docs: Expand notes --- packages/dds/tree/src/simple-tree/schemaTypes.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index 15e2930014db..a6898f5f0626 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -190,7 +190,10 @@ export interface FieldProps { /** * Optional metadata to associate with the field. - * @remarks Note: this metadata is not persisted in the document. + * + * @remarks + * Note: this metadata is not persisted in the document; it only exists locally at runtime. + * So making changes to these values will not affect collaborators. */ readonly metadata?: FieldSchemaMetadata; } @@ -836,7 +839,10 @@ export type TreeLeafValue = number | string | boolean | IFluidHandle | null; export interface NodeSchemaOptions { /** * Optional metadata to associate with the Node Schema. - * @remarks Note: this metadata is not persisted in the document. + * + * @remarks + * Note: this metadata is not persisted in the document; it only exists locally at runtime. + * So making changes to these values will not affect collaborators. */ readonly metadata?: TMetadata; } From 212eea50a46061c5e4733f2a5671ed62c9a1e028 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Mon, 2 Dec 2024 19:32:13 +0000 Subject: [PATCH 07/55] docs: InheritDoc --- packages/dds/tree/src/simple-tree/api/simpleSchema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dds/tree/src/simple-tree/api/simpleSchema.ts b/packages/dds/tree/src/simple-tree/api/simpleSchema.ts index d44cf4f5088e..a1090033708a 100644 --- a/packages/dds/tree/src/simple-tree/api/simpleSchema.ts +++ b/packages/dds/tree/src/simple-tree/api/simpleSchema.ts @@ -22,7 +22,7 @@ export interface SimpleNodeSchemaBase { readonly kind: TNodeKind; /** - * Node metadata. + * {@inheritDoc NodeSchemaOptions.metadata} */ readonly metadata?: NodeSchemaMetadata | undefined; } From 233db92dcaf851d86591ba579b343c6ffe2fcc9a Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Mon, 2 Dec 2024 19:38:35 +0000 Subject: [PATCH 08/55] docs: Update terminology --- packages/dds/tree/src/simple-tree/schemaTypes.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index a6898f5f0626..eeec365f9fda 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -192,8 +192,8 @@ export interface FieldProps { * Optional metadata to associate with the field. * * @remarks - * Note: this metadata is not persisted in the document; it only exists locally at runtime. - * So making changes to these values will not affect collaborators. + * Note: this metadata is not persisted; it is strictly local to the application. + * So, making changes to these values will not affect collaborators. */ readonly metadata?: FieldSchemaMetadata; } @@ -841,8 +841,8 @@ export interface NodeSchemaOptions { * Optional metadata to associate with the Node Schema. * * @remarks - * Note: this metadata is not persisted in the document; it only exists locally at runtime. - * So making changes to these values will not affect collaborators. + * Note: this metadata is not persisted; it is strictly local to the application. + * So, making changes to these values will not affect collaborators. */ readonly metadata?: TMetadata; } From f569711252883f0a2564c3f2a0c1708d53b754f3 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:22:44 +0000 Subject: [PATCH 09/55] revert: Unintended change --- .../src/simple-tree/api/simpleSchemaToJsonSchema.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/api/simpleSchemaToJsonSchema.ts b/packages/dds/tree/src/simple-tree/api/simpleSchemaToJsonSchema.ts index 303ba8ed399c..2fd5ec021f8c 100644 --- a/packages/dds/tree/src/simple-tree/api/simpleSchemaToJsonSchema.ts +++ b/packages/dds/tree/src/simple-tree/api/simpleSchemaToJsonSchema.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { oob, unreachableCase } from "@fluidframework/core-utils/internal"; +import { unreachableCase } from "@fluidframework/core-utils/internal"; import { UsageError } from "@fluidframework/telemetry-utils/internal"; import { ValueSchema } from "../../core/index.js"; import { getOrCreate, hasSingle, type Mutable } from "../../util/index.js"; @@ -194,12 +194,11 @@ function convertMapNodeSchema(schema: SimpleMapNodeSchema): JsonMapNodeSchema { type: "object", _treeNodeSchemaKind: NodeKind.Map, patternProperties: { - "^.*$": - allowedTypes.length === 1 - ? (allowedTypes[0] ?? oob()) - : { - anyOf: allowedTypes, - }, + "^.*$": hasSingle(allowedTypes) + ? allowedTypes[0] + : { + anyOf: allowedTypes, + }, }, }; From c6455af7258cda6a1c99c90a9a6835df63c5dd78 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:03:57 -0800 Subject: [PATCH 10/55] refactor: Apply suggestions from code review Co-authored-by: Noah Encke <78610362+noencke@users.noreply.github.com> --- .changeset/grey-triangles-shout.md | 2 +- packages/dds/tree/src/simple-tree/api/simpleSchema.ts | 2 +- packages/dds/tree/src/simple-tree/schemaTypes.ts | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index bafce6548451..e1e84f1776ce 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -8,7 +8,7 @@ section: tree Allow associating metadata with Node Schema Users of TreeView can now specify metadata when creating Node Schema. -This includes system-understood metadata, i.e., `description`. +This includes system-understood metadata, e.g., `description`. Example: diff --git a/packages/dds/tree/src/simple-tree/api/simpleSchema.ts b/packages/dds/tree/src/simple-tree/api/simpleSchema.ts index a1090033708a..225a035e6abf 100644 --- a/packages/dds/tree/src/simple-tree/api/simpleSchema.ts +++ b/packages/dds/tree/src/simple-tree/api/simpleSchema.ts @@ -22,7 +22,7 @@ export interface SimpleNodeSchemaBase { readonly kind: TNodeKind; /** - * {@inheritDoc NodeSchemaOptions.metadata} + * {@inheritDoc NodeSchemaMetadata} */ readonly metadata?: NodeSchemaMetadata | undefined; } diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index eeec365f9fda..a4a9f3ad131b 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -834,6 +834,7 @@ export type TreeLeafValue = number | string | boolean | IFluidHandle | null; * @typeParam TCustomMetadata - Custom metadata properties to associate with the Node Schema. * See {@link NodeSchemaMetadata.custom}. * + * @sealed * @public */ export interface NodeSchemaOptions { From 37e60881619638f40b3a86bfbd9dd4f41b716690 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 3 Dec 2024 00:19:38 +0000 Subject: [PATCH 11/55] docs: Update API reports --- packages/dds/tree/api-report/tree.alpha.api.md | 2 +- packages/dds/tree/api-report/tree.beta.api.md | 2 +- packages/dds/tree/api-report/tree.legacy.alpha.api.md | 2 +- packages/dds/tree/api-report/tree.legacy.public.api.md | 2 +- packages/dds/tree/api-report/tree.public.api.md | 2 +- .../fluid-framework/api-report/fluid-framework.alpha.api.md | 3 ++- .../fluid-framework/api-report/fluid-framework.beta.api.md | 2 +- .../api-report/fluid-framework.legacy.alpha.api.md | 2 +- .../api-report/fluid-framework.legacy.public.api.md | 2 +- .../fluid-framework/api-report/fluid-framework.public.api.md | 2 +- 10 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 3672ed745887..8972fcd8e18d 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -483,7 +483,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index b3bdacdc77d9..ab86c2960154 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -272,7 +272,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index 565922da09b4..1889d2dca3af 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -267,7 +267,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index 3a803bb36980..7a5c11d8f66b 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -267,7 +267,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index 3a803bb36980..7a5c11d8f66b 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -267,7 +267,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 85e6f639cae9..4f768e697c11 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -735,6 +735,7 @@ export type JsonNodeSchema = JsonLeafNodeSchema | JsonMapNodeSchema | JsonArrayN // @alpha @sealed export interface JsonNodeSchemaBase { + readonly description?: string | undefined; readonly _treeNodeSchemaKind: TNodeKind; readonly type: TJsonSchemaType; } @@ -838,7 +839,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index 171a2b180ff6..bdc716e074ba 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -625,7 +625,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index c194c8ea90f2..f5a4a25f38d7 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -923,7 +923,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index c18784866a15..edeb9bde123f 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -656,7 +656,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index c5fd2b422b89..dd481fdf2721 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -620,7 +620,7 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public +// @public @sealed export interface NodeSchemaOptions { readonly metadata?: TMetadata; } From ccc0be8987ad2b3c61f4ef4eb4f4ece0928341bc Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 3 Dec 2024 00:19:50 +0000 Subject: [PATCH 12/55] refactor: Consistent typing --- packages/dds/tree/src/simple-tree/arrayNode.ts | 2 +- packages/dds/tree/src/simple-tree/leafNodeSchema.ts | 2 +- packages/dds/tree/src/simple-tree/mapNode.ts | 2 +- packages/dds/tree/src/simple-tree/objectNode.ts | 2 +- packages/dds/tree/src/test/simple-tree/core/types.spec.ts | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/arrayNode.ts b/packages/dds/tree/src/simple-tree/arrayNode.ts index 3321100a5d59..47ad5ac9e4c4 100644 --- a/packages/dds/tree/src/simple-tree/arrayNode.ts +++ b/packages/dds/tree/src/simple-tree/arrayNode.ts @@ -1161,7 +1161,7 @@ export function arraySchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } - public static readonly metadata: TMetadata | undefined = metadata; + public static readonly metadata?: TMetadata = metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/simple-tree/leafNodeSchema.ts b/packages/dds/tree/src/simple-tree/leafNodeSchema.ts index bb885c3a8c03..45da068761a3 100644 --- a/packages/dds/tree/src/simple-tree/leafNodeSchema.ts +++ b/packages/dds/tree/src/simple-tree/leafNodeSchema.ts @@ -31,7 +31,7 @@ export class LeafNodeSchema public readonly info: T; public readonly implicitlyConstructable = true as const; public readonly childTypes: ReadonlySet = new Set(); - public readonly metadata: NodeSchemaMetadata | undefined = undefined; // TODO + public readonly metadata?: NodeSchemaMetadata | undefined = undefined; public create(data: TreeValue | FlexTreeNode): TreeValue { if (isFlexTreeNode(data)) { diff --git a/packages/dds/tree/src/simple-tree/mapNode.ts b/packages/dds/tree/src/simple-tree/mapNode.ts index d51dbabcea2b..0c9ba815f0a3 100644 --- a/packages/dds/tree/src/simple-tree/mapNode.ts +++ b/packages/dds/tree/src/simple-tree/mapNode.ts @@ -286,7 +286,7 @@ export function mapSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } - public static readonly metadata = metadata; + public static readonly metadata?: TMetadata = metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/simple-tree/objectNode.ts b/packages/dds/tree/src/simple-tree/objectNode.ts index c477705049da..ca2834591c75 100644 --- a/packages/dds/tree/src/simple-tree/objectNode.ts +++ b/packages/dds/tree/src/simple-tree/objectNode.ts @@ -458,7 +458,7 @@ export function objectSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } - public static readonly metadata = metadata; + public static readonly metadata?: TMetadata = metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/test/simple-tree/core/types.spec.ts b/packages/dds/tree/src/test/simple-tree/core/types.spec.ts index 18b9a72cdb43..90097e53890e 100644 --- a/packages/dds/tree/src/test/simple-tree/core/types.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/core/types.spec.ts @@ -136,7 +136,7 @@ describe("simple-tree types", () => { public static readonly identifier = "Subclass"; public static readonly info = numberSchema; public static readonly implicitlyConstructable: false; - public static readonly metadata: NodeSchemaMetadata | undefined = undefined; + public static readonly metadata?: NodeSchemaMetadata = undefined; public static override prepareInstance( this: typeof TreeNodeValid, @@ -237,7 +237,7 @@ describe("simple-tree types", () => { public static readonly info = numberSchema; public static readonly implicitlyConstructable: false; public static readonly childTypes: ReadonlySet = new Set(); - public static readonly metadata: NodeSchemaMetadata | undefined = undefined; + public static readonly metadata?: NodeSchemaMetadata = undefined; public static override buildRawNode( this: typeof TreeNodeValid, @@ -291,7 +291,7 @@ describe("simple-tree types", () => { public static readonly info = numberSchema; public static readonly implicitlyConstructable: false; public static readonly childTypes: ReadonlySet = new Set(); - public static readonly metadata: NodeSchemaMetadata | undefined = undefined; + public static readonly metadata?: NodeSchemaMetadata = undefined; public static override buildRawNode( this: typeof TreeNodeValid, From fb10e722580aeee71371e69840c7fddaeb3c1e05 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 10 Dec 2024 23:24:20 +0000 Subject: [PATCH 13/55] tools: Update spelling dictionary --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 62a869fe150e..b40e1694e0d1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -43,6 +43,7 @@ "handletable", "incrementality", "injective", + "insertable", "losslessly", "mitigations", "mocharc", @@ -61,7 +62,7 @@ "unacked", "unaugmented", "undoprovider", - "unsequenced", + "unsequenced" ], // Enable biome as default formatter, and disable rules that disagree with it From 9e1e1fe3507cd468915402fa4cda677653ae4ea2 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 10 Dec 2024 23:35:15 +0000 Subject: [PATCH 14/55] refactor: Expose `withMetadata` function to replace new SchemaFactory parameters --- .changeset/grey-triangles-shout.md | 40 ++-- .../dds/tree/api-report/tree.alpha.api.md | 19 +- packages/dds/tree/api-report/tree.beta.api.md | 16 +- .../tree/api-report/tree.legacy.alpha.api.md | 16 +- .../tree/api-report/tree.legacy.public.api.md | 16 +- .../dds/tree/api-report/tree.public.api.md | 16 +- packages/dds/tree/src/index.ts | 1 + .../dds/tree/src/simple-tree/api/index.ts | 2 +- .../tree/src/simple-tree/api/schemaFactory.ts | 175 +++++++++--------- .../dds/tree/src/simple-tree/arrayNode.ts | 7 +- packages/dds/tree/src/simple-tree/index.ts | 1 + .../tree/src/simple-tree/leafNodeSchema.ts | 2 - packages/dds/tree/src/simple-tree/mapNode.ts | 7 +- .../dds/tree/src/simple-tree/objectNode.ts | 7 +- .../simple-tree/api/getJsonSchema.spec.ts | 20 +- .../simple-tree/api/schemaFactory.spec.ts | 30 +-- .../api/schemaFactoryRecursive.spec.ts | 29 +-- 17 files changed, 193 insertions(+), 211 deletions(-) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index e1e84f1776ce..a746271687c3 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -7,20 +7,22 @@ section: tree Allow associating metadata with Node Schema -Users of TreeView can now specify metadata when creating Node Schema. -This includes system-understood metadata, e.g., `description`. +Users of TreeView can now specify metadata when creating Node Schema via the experimental (alpha) `withMetadata` function. +This metadata may include system-understood properties like `description`. Example: ```typescript -class Point extends schemaFactory.object("Point", { - x: schemaFactory.required(schemaFactory.number), - y: schemaFactory.required(schemaFactory.number), -}, -{ - metadata: { description: "A point in 2D space" } -}) {} +class Point extends withMetadata( + schemaFactory.object("Point", { + x: schemaFactory.required(schemaFactory.number), + y: schemaFactory.required(schemaFactory.number), + }), + { + description: "A point in 2D space", + }, +) {} ``` @@ -46,23 +48,23 @@ interface AppMetadata { searchIgnore?: boolean; } -class Point extends schemaFactory.object("Point", { - x: schemaFactory.required(schemaFactory.number), - y: schemaFactory.required(schemaFactory.number), -}, -{ - metadata: { +class Point extends withMetadata( + schemaFactory.object("Point", { + x: schemaFactory.required(schemaFactory.number), + y: schemaFactory.required(schemaFactory.number), + }), + { description: "A point in 2D space", custom: { searchIgnore: true, - } - } -}) {} + }, + }, +) {} ``` Search can then be implemented to look for the appropriate metadata, and leverage it to omit the unwanted position data from search. -**Note:** these changes add a new property to the base type from which all node schema derive. +**Note:** these changes add the new property "metadata" to the base type from which all node schema derive. If you have existing node schema subclasses that include a property of this name, there is a chance for potential conflict here that could be breaking. If you encounter issues here, consider renaming your property. diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 8972fcd8e18d..11273bd47fad 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -610,27 +610,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -1006,6 +1006,9 @@ export interface ViewContent { readonly tree: JsonCompatible; } +// @alpha +export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: TMetadataOut): TreeNodeSchemaClass; + // @public @sealed export interface WithType { // @deprecated diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index ab86c2960154..77fc7a8a21bc 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -371,27 +371,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index 1889d2dca3af..e3de8d25e3a0 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -366,27 +366,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index 7a5c11d8f66b..147ac0ea37b7 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -366,27 +366,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index 7a5c11d8f66b..147ac0ea37b7 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -366,27 +366,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/src/index.ts b/packages/dds/tree/src/index.ts index 4cdf0fcd95c6..4e7e973e13d3 100644 --- a/packages/dds/tree/src/index.ts +++ b/packages/dds/tree/src/index.ts @@ -128,6 +128,7 @@ export { type FactoryContentObject, type ReadableField, type ReadSchema, + withMetadata, // test recursive schema for checking that d.ts files handles schema correctly test_RecursiveObject, test_RecursiveObject_base, diff --git a/packages/dds/tree/src/simple-tree/api/index.ts b/packages/dds/tree/src/simple-tree/api/index.ts index 83fda6bf3356..c8718c885b7b 100644 --- a/packages/dds/tree/src/simple-tree/api/index.ts +++ b/packages/dds/tree/src/simple-tree/api/index.ts @@ -17,7 +17,7 @@ export { type TreeBranchEvents, asTreeViewAlpha, } from "./tree.js"; -export { SchemaFactory, type ScopedSchemaName } from "./schemaFactory.js"; +export { SchemaFactory, type ScopedSchemaName, withMetadata } from "./schemaFactory.js"; export type { ValidateRecursiveSchema, FixRecursiveArraySchema, diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 99c54a5f13e8..ac213c4bcea8 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -38,7 +38,6 @@ import { type DefaultProvider, getDefaultProvider, type NodeSchemaMetadata, - type NodeSchemaOptions, } from "../schemaTypes.js"; import { inPrototypeChain } from "../core/index.js"; import type { @@ -48,6 +47,7 @@ import type { TreeNodeSchemaClass, TreeNodeSchemaNonClass, TreeNodeSchemaBoth, + TreeNode, } from "../core/index.js"; import { type TreeArrayNode, arraySchema } from "../arrayNode.js"; import { @@ -324,22 +324,18 @@ export class SchemaFactory< public object< const Name extends TName, const T extends RestrictiveStringRecord, - const TMetadata extends NodeSchemaMetadata, >( name: Name, fields: T, - options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, - T, - never, - TMetadata + T > { - return objectSchema(this.scoped(name), fields, true, options?.metadata); + return objectSchema(this.scoped(name), fields, true); } /** @@ -387,14 +383,9 @@ export class SchemaFactory< * class NamedMap extends factory.map("name", factory.number) {} * ``` */ - public map< - Name extends TName, - const T extends ImplicitAllowedTypes, - const TMetadata extends NodeSchemaMetadata, - >( + public map( name: Name, allowedTypes: T, - options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Map, @@ -402,8 +393,7 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined, - TMetadata + undefined >; /** @@ -414,10 +404,9 @@ export class SchemaFactory< * This seems like a TypeScript bug getting variance backwards for overload return types since it's erroring when the relation between the overload * and the implementation is type safe, and forcing an unsafe typing instead. */ - public map( + public map( nameOrAllowedTypes: TName | ((T & TreeNodeSchema) | readonly TreeNodeSchema[]), allowedTypes?: T, - options?: NodeSchemaOptions, ): TreeNodeSchema, MapNodeInsertableData, true, T> { if (allowedTypes === undefined) { const types = nameOrAllowedTypes as (T & TreeNodeSchema) | readonly TreeNodeSchema[]; @@ -431,7 +420,6 @@ export class SchemaFactory< nameOrAllowedTypes as T, false, true, - options?.metadata, ) as TreeNodeSchema, ) as TreeNodeSchemaBoth< string, @@ -440,27 +428,18 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined, - TMetadata + undefined >; } - // To actually have type safety, assign to the type this method should return before implicitly upcasting when returning. + // To actually have type safety, assign to the type this method should return before implicitly up-casting when returning. const out: TreeNodeSchemaBoth< string, NodeKind.Map, TreeMapNode, MapNodeInsertableData, true, - T, - undefined, - TMetadata - > = this.namedMap( - nameOrAllowedTypes as TName, - allowedTypes, - true, - true, - options?.metadata, - ); + T + > = this.namedMap(nameOrAllowedTypes as TName, allowedTypes, true, true); return out; } @@ -473,13 +452,11 @@ export class SchemaFactory< Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, - TMetadata extends NodeSchemaMetadata, >( name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable, - metadata: TMetadata | undefined, ): TreeNodeSchemaBoth< ScopedSchemaName, NodeKind.Map, @@ -487,8 +464,7 @@ export class SchemaFactory< MapNodeInsertableData, ImplicitlyConstructable, T, - undefined, - TMetadata + undefined > { return mapSchema( this.scoped(name), @@ -496,7 +472,6 @@ export class SchemaFactory< implicitlyConstructable, // The current policy is customizable nodes don't get fake prototypes. !customizable, - metadata, ); } @@ -557,14 +532,9 @@ export class SchemaFactory< * * {@label NAMED} */ - public array< - const Name extends TName, - const T extends ImplicitAllowedTypes, - const TMetadata extends NodeSchemaMetadata, - >( + public array( name: Name, allowedTypes: T, - options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Array, @@ -572,8 +542,7 @@ export class SchemaFactory< Iterable>, true, T, - undefined, - TMetadata + undefined >; /** @@ -582,13 +551,9 @@ export class SchemaFactory< * @privateRemarks * This should return TreeNodeSchemaBoth: see note on "map" implementation for details. */ - public array< - const T extends ImplicitAllowedTypes, - const TMetadata extends NodeSchemaMetadata, - >( + public array( nameOrAllowedTypes: TName | ((T & TreeNodeSchema) | readonly TreeNodeSchema[]), allowedTypes?: T, - options?: NodeSchemaOptions, ): TreeNodeSchema< ScopedSchemaName, NodeKind.Array, @@ -601,7 +566,7 @@ export class SchemaFactory< const types = nameOrAllowedTypes as (T & TreeNodeSchema) | readonly TreeNodeSchema[]; const fullName = structuralName("Array", types); return getOrCreate(this.structuralTypes, fullName, () => - this.namedArray(fullName, nameOrAllowedTypes as T, false, true, options?.metadata), + this.namedArray(fullName, nameOrAllowedTypes as T, false, true), ) as TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Array, @@ -609,8 +574,7 @@ export class SchemaFactory< Iterable>, true, T, - undefined, - TMetadata + undefined >; } const out: TreeNodeSchemaBoth< @@ -619,16 +583,8 @@ export class SchemaFactory< TreeArrayNode, Iterable>, true, - T, - undefined, - TMetadata - > = this.namedArray( - nameOrAllowedTypes as TName, - allowedTypes, - true, - true, - options?.metadata, - ); + T + > = this.namedArray(nameOrAllowedTypes as TName, allowedTypes, true, true); return out; } @@ -645,13 +601,11 @@ export class SchemaFactory< Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, - const TMetadata extends NodeSchemaMetadata, >( name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable, - metadata: TMetadata | undefined, ): TreeNodeSchemaBoth< ScopedSchemaName, NodeKind.Array, @@ -659,16 +613,9 @@ export class SchemaFactory< Iterable>, ImplicitlyConstructable, T, - undefined, - TMetadata + undefined > { - return arraySchema( - this.scoped(name), - allowedTypes, - implicitlyConstructable, - customizable, - metadata, - ); + return arraySchema(this.scoped(name), allowedTypes, implicitlyConstructable, customizable); } /** @@ -787,22 +734,18 @@ export class SchemaFactory< public objectRecursive< const Name extends TName, const T extends Unenforced>, - const TMetadata extends NodeSchemaMetadata, - >(name: Name, t: T, options?: NodeSchemaOptions) { + >(name: Name, t: T) { type TScopedName = ScopedSchemaName; return this.object( name, t as T & RestrictiveStringRecord, - options, ) as unknown as TreeNodeSchemaClass< TScopedName, NodeKind.Object, TreeObjectNodeUnsafe, object & InsertableObjectFromSchemaRecordUnsafe, false, - T, - never, - TMetadata + T >; } @@ -817,14 +760,12 @@ export class SchemaFactory< public arrayRecursive< const Name extends TName, const T extends Unenforced, - const TMetadata extends NodeSchemaMetadata, - >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { + >(name: Name, allowedTypes: T) { const RecursiveArray = this.namedArray( name, allowedTypes as T & ImplicitAllowedTypes, true, false, - options?.metadata, ); return RecursiveArray as TreeNodeSchemaClass< @@ -847,8 +788,7 @@ export class SchemaFactory< }, false, T, - undefined, - TMetadata + undefined >; } @@ -860,11 +800,10 @@ export class SchemaFactory< * See {@link ValidateRecursiveSchema} for additional information about using recursive schema. */ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - public mapRecursive< - Name extends TName, - const T extends Unenforced, - const TMetadata extends NodeSchemaMetadata, - >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { + public mapRecursive>( + name: Name, + allowedTypes: T, + ) { const MapSchema = this.namedMap( name, allowedTypes as T & ImplicitAllowedTypes, @@ -872,7 +811,6 @@ export class SchemaFactory< // Setting this (implicitlyConstructable) to true seems to work ok currently, but not for other node kinds. // Supporting this could be fragile and might break other future changes, so it's being kept as false for now. false, - options?.metadata, ); return MapSchema as TreeNodeSchemaClass< @@ -904,8 +842,7 @@ export class SchemaFactory< }, false, T, - undefined, - TMetadata + undefined >; } } @@ -957,3 +894,57 @@ export function markSchemaMostDerived(schema: TreeNodeSchema): void { (schema as typeof TreeNodeValid & TreeNodeSchema).markMostDerived(); } + +/** + * TODO + * @param nodeSchema - TODO + * @param metadata - TODO + * + * @alpha + */ +export function withMetadata< + const TName extends string = string, + const TKind extends NodeKind = NodeKind, + const TNode extends TreeNode = TreeNode, + const TInsertable = never, + const ImplicitlyConstructable extends boolean = boolean, + const Info = unknown, + const TConstructorExtra = never, + const TMetadataIn extends NodeSchemaMetadata = NodeSchemaMetadata, + const TMetadataOut extends TMetadataIn = TMetadataIn, +>( + nodeSchema: TreeNodeSchemaClass< + TName, + TKind, + TNode, + TInsertable, + ImplicitlyConstructable, + Info, + TConstructorExtra, + TMetadataIn + >, + metadata: TMetadataOut, +): TreeNodeSchemaClass< + TName, + TKind, + TNode, + TInsertable, + ImplicitlyConstructable, + Info, + TConstructorExtra, + TMetadataOut +> { + class Derived extends nodeSchema { + public static readonly metadata?: TMetadataOut | undefined = metadata; + } + return Derived as unknown as TreeNodeSchemaClass< + TName, + TKind, + TNode, + TInsertable, + ImplicitlyConstructable, + Info, + TConstructorExtra, + TMetadataOut + >; +} diff --git a/packages/dds/tree/src/simple-tree/arrayNode.ts b/packages/dds/tree/src/simple-tree/arrayNode.ts index 47ad5ac9e4c4..01b9e1108732 100644 --- a/packages/dds/tree/src/simple-tree/arrayNode.ts +++ b/packages/dds/tree/src/simple-tree/arrayNode.ts @@ -18,7 +18,6 @@ import { normalizeAllowedTypes, type ImplicitAllowedTypes, type InsertableTreeNodeFromImplicitAllowedTypes, - type NodeSchemaMetadata, type TreeLeafValue, type TreeNodeFromImplicitAllowedTypes, } from "./schemaTypes.js"; @@ -1063,13 +1062,11 @@ export function arraySchema< TName extends string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, - const TMetadata extends NodeSchemaMetadata, >( identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, customizable: boolean, - metadata: TMetadata | undefined, ) { type Output = TreeNodeSchemaBoth< TName, @@ -1078,8 +1075,7 @@ export function arraySchema< Iterable>, ImplicitlyConstructable, T, - undefined, - TMetadata + undefined >; const lazyChildTypes = new Lazy(() => normalizeAllowedTypes(info)); @@ -1161,7 +1157,6 @@ export function arraySchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } - public static readonly metadata?: TMetadata = metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/simple-tree/index.ts b/packages/dds/tree/src/simple-tree/index.ts index 7b83fa9acd29..ac2d93746448 100644 --- a/packages/dds/tree/src/simple-tree/index.ts +++ b/packages/dds/tree/src/simple-tree/index.ts @@ -122,6 +122,7 @@ export { type CustomTreeNode, type CustomTreeValue, tryStoredSchemaAsArray, + withMetadata, } from "./api/index.js"; export { type NodeFromSchema, diff --git a/packages/dds/tree/src/simple-tree/leafNodeSchema.ts b/packages/dds/tree/src/simple-tree/leafNodeSchema.ts index 45da068761a3..5612de18c0f6 100644 --- a/packages/dds/tree/src/simple-tree/leafNodeSchema.ts +++ b/packages/dds/tree/src/simple-tree/leafNodeSchema.ts @@ -12,7 +12,6 @@ import { valueSchemaAllows, } from "../feature-libraries/index.js"; import { NodeKind, type TreeNodeSchema, type TreeNodeSchemaNonClass } from "./core/index.js"; -import type { NodeSchemaMetadata } from "./schemaTypes.js"; /** * Instances of this class are schema for leaf nodes. @@ -31,7 +30,6 @@ export class LeafNodeSchema public readonly info: T; public readonly implicitlyConstructable = true as const; public readonly childTypes: ReadonlySet = new Set(); - public readonly metadata?: NodeSchemaMetadata | undefined = undefined; public create(data: TreeValue | FlexTreeNode): TreeValue { if (isFlexTreeNode(data)) { diff --git a/packages/dds/tree/src/simple-tree/mapNode.ts b/packages/dds/tree/src/simple-tree/mapNode.ts index 0c9ba815f0a3..f43a0c15a9a9 100644 --- a/packages/dds/tree/src/simple-tree/mapNode.ts +++ b/packages/dds/tree/src/simple-tree/mapNode.ts @@ -17,7 +17,6 @@ import { normalizeAllowedTypes, type ImplicitAllowedTypes, type InsertableTreeNodeFromImplicitAllowedTypes, - type NodeSchemaMetadata, type TreeNodeFromImplicitAllowedTypes, } from "./schemaTypes.js"; import { @@ -236,13 +235,11 @@ export function mapSchema< TName extends string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, - const TMetadata extends NodeSchemaMetadata, >( identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, useMapPrototype: boolean, - metadata: TMetadata | undefined, ) { const lazyChildTypes = new Lazy(() => normalizeAllowedTypes(info)); @@ -286,7 +283,6 @@ export function mapSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } - public static readonly metadata?: TMetadata = metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { @@ -303,8 +299,7 @@ export function mapSchema< MapNodeInsertableData, ImplicitlyConstructable, T, - undefined, - TMetadata + undefined > = Schema; return schemaErased; } diff --git a/packages/dds/tree/src/simple-tree/objectNode.ts b/packages/dds/tree/src/simple-tree/objectNode.ts index ca2834591c75..5d692dc6d13a 100644 --- a/packages/dds/tree/src/simple-tree/objectNode.ts +++ b/packages/dds/tree/src/simple-tree/objectNode.ts @@ -26,7 +26,6 @@ import { normalizeFieldSchema, type ImplicitAllowedTypes, FieldKind, - type NodeSchemaMetadata, } from "./schemaTypes.js"; import { type TreeNodeSchema, @@ -327,14 +326,11 @@ export function objectSchema< TName extends string, const T extends RestrictiveStringRecord, const ImplicitlyConstructable extends boolean, - const TMetadata extends NodeSchemaMetadata, >( identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, - metadata: TMetadata | undefined, -): ObjectNodeSchema & - ObjectNodeSchemaInternalData { +): ObjectNodeSchema & ObjectNodeSchemaInternalData { // Ensure no collisions between final set of property keys, and final set of stored keys (including those // implicitly derived from property keys) assertUniqueKeys(identifier, info); @@ -458,7 +454,6 @@ export function objectSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } - public static readonly metadata?: TMetadata = metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts index f181a1859b22..011565d1559a 100644 --- a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts @@ -9,6 +9,7 @@ import { NodeKind, SchemaFactory, type JsonTreeSchema, + withMetadata, } from "../../../simple-tree/index.js"; import { hydrate } from "../utils.js"; @@ -126,8 +127,8 @@ describe("getJsonSchema", () => { it("Array schema", () => { const schemaFactory = new SchemaFactory("test"); - const Schema = schemaFactory.array("array", schemaFactory.string, { - metadata: { description: "An array of strings" }, + const Schema = withMetadata(schemaFactory.array("array", schemaFactory.string), { + description: "An array of strings", }); const actual = getJsonSchema(Schema); @@ -165,8 +166,8 @@ describe("getJsonSchema", () => { it("Map schema", () => { const schemaFactory = new SchemaFactory("test"); - const Schema = schemaFactory.map("map", schemaFactory.string, { - metadata: { description: "A map containing strings" }, + const Schema = withMetadata(schemaFactory.map("map", schemaFactory.string), { + description: "A map containing strings", }); const actual = getJsonSchema(Schema); @@ -225,19 +226,16 @@ describe("getJsonSchema", () => { it("Object schema", () => { const schemaFactory = new SchemaFactory("test"); - const Schema = schemaFactory.object( - "object", - { + const Schema = withMetadata( + schemaFactory.object("object", { foo: schemaFactory.optional(schemaFactory.number, { metadata: { description: "A number representing the concept of Foo." }, }), bar: schemaFactory.required(schemaFactory.string, { metadata: { description: "A string representing the concept of Bar." }, }), - }, - { - metadata: { description: "An object with Foo and Bar." }, - }, + }), + { description: "An object with Foo and Bar." }, ); const actual = getJsonSchema(Schema); diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 6c53c26b7bb8..61dbd31d9f65 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -5,7 +5,7 @@ import { strict as assert } from "node:assert"; -import { unreachableCase } from "@fluidframework/core-utils/internal"; +import { oob, unreachableCase } from "@fluidframework/core-utils/internal"; import { createIdCompressor } from "@fluidframework/id-compressor/internal"; import { MockFluidDataStoreRuntime, @@ -36,6 +36,7 @@ import type { ObjectNodeSchema } from "../../../simple-tree/objectNodeTypes.js"; import { SchemaFactory, schemaFromValue, + withMetadata, // eslint-disable-next-line import/no-internal-modules } from "../../../simple-tree/api/schemaFactory.js"; import type { @@ -363,14 +364,13 @@ describe("schemaFactory", () => { ); }); - it("Node schema metadata", () => { + it("withMetadata", () => { const factory = new SchemaFactory(""); - class Foo extends factory.object( - "Foo", - { bar: factory.number }, - { metadata: { description: "An object", custom: { baz: true } } }, - ) {} + class Foo extends withMetadata(factory.object("Foo", { bar: factory.number }), { + description: "An object", + custom: { baz: true }, + }) {} assert.deepEqual(Foo.metadata, { description: "An object", @@ -475,7 +475,7 @@ describe("schemaFactory", () => { ); const stuff = view.root.stuff; assert(stuff instanceof NodeList); - const item = stuff[0]; + const item = stuff[0] ?? oob(); const s: string = item.text; assert.equal(s, "hi"); }); @@ -559,11 +559,12 @@ describe("schemaFactory", () => { const namedInstance = new NamedList([5]); }); - it("Node schema metadata", () => { + it("withMetadata", () => { const factory = new SchemaFactory(""); - class Foo extends factory.array("Foo", factory.number, { - metadata: { description: "An array of numbers", custom: { baz: true } }, + class Foo extends withMetadata(factory.array("Foo", factory.number), { + description: "An array of numbers", + custom: { baz: true }, }) {} assert.deepEqual(Foo.metadata, { @@ -628,11 +629,12 @@ describe("schemaFactory", () => { const namedInstance = new NamedMap(new Map([["x", 5]])); }); - it("Node schema metadata", () => { + it("withMetadata", () => { const factory = new SchemaFactory(""); - class Foo extends factory.map("Foo", factory.number, { - metadata: { description: "A map containing numbers", custom: { baz: true } }, + class Foo extends withMetadata(factory.map("Foo", factory.number), { + description: "A map containing numbers", + custom: { baz: true }, }) {} assert.deepEqual(Foo.metadata, { diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts index 0cdfdb9a9219..3e39c5854bf1 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts @@ -22,6 +22,7 @@ import { type FlexListToUnion, type ApplyKindInput, type NodeBuilderData, + withMetadata, } from "../../../simple-tree/index.js"; import type { ValidateRecursiveSchema, @@ -460,16 +461,14 @@ describe("SchemaFactory Recursive methods", () => { it("Node schema metadata", () => { const factory = new SchemaFactory(""); - class Foo extends factory.objectRecursive( - "Foo", - { bar: () => Bar }, - { metadata: { description: "A recursive object called Foo", custom: { baz: true } } }, - ) {} - class Bar extends factory.objectRecursive( - "Bar", - { foo: () => Foo }, - { metadata: { description: "A recursive object called Bar", custom: { baz: false } } }, - ) {} + class Foo extends withMetadata(factory.objectRecursive("Foo", { bar: () => Bar }), { + description: "A recursive object called Foo", + custom: { baz: true }, + }) {} + class Bar extends withMetadata(factory.objectRecursive("Bar", { foo: () => Foo }), { + description: "A recursive object called Bar", + custom: { baz: false }, + }) {} assert.deepEqual(Foo.metadata, { description: "A recursive object called Foo", @@ -608,8 +607,9 @@ describe("SchemaFactory Recursive methods", () => { class Foo extends factory.objectRecursive("Foo", { fooList: sf.arrayRecursive("FooList", [() => Foo]), }) {} - class FooList extends factory.arrayRecursive("FooList", [() => Foo], { - metadata: { description: "A recursive list", custom: { baz: true } }, + class FooList extends withMetadata(factory.arrayRecursive("FooList", [() => Foo]), { + description: "A recursive list", + custom: { baz: true }, }) {} assert.deepEqual(FooList.metadata, { @@ -671,8 +671,9 @@ describe("SchemaFactory Recursive methods", () => { class Foo extends factory.objectRecursive("Foo", { fooList: sf.arrayRecursive("FooList", [() => Foo]), }) {} - class FooList extends factory.mapRecursive("FooList", [() => Foo], { - metadata: { description: "A recursive map", custom: { baz: true } }, + class FooList extends withMetadata(factory.mapRecursive("FooList", [() => Foo]), { + description: "A recursive map", + custom: { baz: true }, }) {} assert.deepEqual(FooList.metadata, { From 471ae1d2928f69dede7378806d6ded34c050c3f4 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 10 Dec 2024 23:38:32 +0000 Subject: [PATCH 15/55] refactor: Remove unused type --- .../dds/tree/api-report/tree.alpha.api.md | 5 ----- packages/dds/tree/api-report/tree.beta.api.md | 5 ----- .../tree/api-report/tree.legacy.alpha.api.md | 5 ----- .../tree/api-report/tree.legacy.public.api.md | 5 ----- .../dds/tree/api-report/tree.public.api.md | 5 ----- packages/dds/tree/src/index.ts | 1 - packages/dds/tree/src/simple-tree/index.ts | 1 - .../dds/tree/src/simple-tree/schemaTypes.ts | 22 ------------------- 8 files changed, 49 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 11273bd47fad..938893bee236 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -483,11 +483,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @alpha export const noopValidator: JsonValidator; diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index 77fc7a8a21bc..d6375f414c7e 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -272,11 +272,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index e3de8d25e3a0..d853288e07aa 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -267,11 +267,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index 147ac0ea37b7..aaaf6c3d7c30 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -267,11 +267,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index 147ac0ea37b7..aaaf6c3d7c30 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -267,11 +267,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; diff --git a/packages/dds/tree/src/index.ts b/packages/dds/tree/src/index.ts index 4e7e973e13d3..c90cc0747cb2 100644 --- a/packages/dds/tree/src/index.ts +++ b/packages/dds/tree/src/index.ts @@ -177,7 +177,6 @@ export { type TreeBranchEvents, asTreeViewAlpha, type NodeSchemaMetadata, - type NodeSchemaOptions, } from "./simple-tree/index.js"; export { SharedTree, diff --git a/packages/dds/tree/src/simple-tree/index.ts b/packages/dds/tree/src/simple-tree/index.ts index ac2d93746448..c7766d9ce446 100644 --- a/packages/dds/tree/src/simple-tree/index.ts +++ b/packages/dds/tree/src/simple-tree/index.ts @@ -156,7 +156,6 @@ export { type ReadableField, type ReadSchema, type NodeSchemaMetadata, - type NodeSchemaOptions, } from "./schemaTypes.js"; export { getTreeNodeForField, diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index a4a9f3ad131b..e8b49753192c 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -828,31 +828,9 @@ export type NodeBuilderData { - /** - * Optional metadata to associate with the Node Schema. - * - * @remarks - * Note: this metadata is not persisted; it is strictly local to the application. - * So, making changes to these values will not affect collaborators. - */ - readonly metadata?: TMetadata; -} - /** * Metadata associated with a Node Schema. * - * @remarks Specified via {@link NodeSchemaOptions.metadata}. - * * @sealed * @public */ From fc48fe1291b91f26c4f46d128f5d1a496d6e8b3d Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 10 Dec 2024 23:49:08 +0000 Subject: [PATCH 16/55] docs: Update API reports --- .../api-report/fluid-framework.alpha.api.md | 24 +++++++++---------- .../api-report/fluid-framework.beta.api.md | 21 +++++++--------- .../fluid-framework.legacy.alpha.api.md | 21 +++++++--------- .../fluid-framework.legacy.public.api.md | 21 +++++++--------- .../api-report/fluid-framework.public.api.md | 21 +++++++--------- 5 files changed, 43 insertions(+), 65 deletions(-) diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 4f768e697c11..2664fa7b2370 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -839,11 +839,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @alpha export const noopValidator: JsonValidator; @@ -972,27 +967,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -1390,6 +1385,9 @@ export interface ViewContent { readonly tree: JsonCompatible; } +// @alpha +export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: TMetadataOut): TreeNodeSchemaClass; + // @public @sealed export interface WithType { // @deprecated diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index bdc716e074ba..f5c3892ff68c 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -625,11 +625,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -730,27 +725,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index f5a4a25f38d7..0ce63a9faa16 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -923,11 +923,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -1028,27 +1023,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index edeb9bde123f..f8aa4e32e068 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -656,11 +656,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -761,27 +756,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index dd481fdf2721..d827a360996b 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -620,11 +620,6 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } -// @public @sealed -export interface NodeSchemaOptions { - readonly metadata?: TMetadata; -} - // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -725,27 +720,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TMetadata>; - arrayRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TMetadata>; - mapRecursive, const TMetadata extends NodeSchemaMetadata>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; - object, const TMetadata extends NodeSchemaMetadata>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TMetadata>; - objectRecursive>, const TMetadata extends NodeSchemaMetadata>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; From 957e2025baf22a61589d049378e5bceb282c379e Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:57:15 -0800 Subject: [PATCH 17/55] docs: Update changeset wording Co-authored-by: Tyler Butler --- .changeset/grey-triangles-shout.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index a746271687c3..20d6f91683cd 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -5,7 +5,7 @@ section: tree --- -Allow associating metadata with Node Schema +Metadata can now be associated with Node Schema Users of TreeView can now specify metadata when creating Node Schema via the experimental (alpha) `withMetadata` function. This metadata may include system-understood properties like `description`. @@ -27,12 +27,12 @@ class Point extends withMetadata( ``` Functionality like the experimental conversion of Tree Schema to [JSON Schema](https://json-schema.org/) (`getJsonSchema`) leverages such system-understood metadata to generate useful information. -In the case of the `description` property, this is mapped directly to the `description` property supported by JSON Schema. +In the case of the `description` property, it is mapped directly to the `description` property supported by JSON Schema. Custom, user-defined properties can also be specified. -These properties will not be leveraged by the system by default, but can be used as a handy means of associating common application-specific properties with Field Schema. +These properties will not be used by the system by default, but can be used to associate common application-specific properties with Field Schema. -Example: +#### Example An application is implementing search functionality. By default, the app author wishes for all app content to be potentially indexable by search, unless otherwise specified. From 8abd211349b616a1800f6e224078f13f8964fd8c Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:01:24 -0800 Subject: [PATCH 18/55] revert: Unwanted changes --- packages/dds/tree/src/simple-tree/api/schemaFactory.ts | 6 ++++-- packages/dds/tree/src/test/simple-tree/core/types.spec.ts | 3 --- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index ac213c4bcea8..f728380d15e8 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -438,7 +438,8 @@ export class SchemaFactory< TreeMapNode, MapNodeInsertableData, true, - T + T, + undefined > = this.namedMap(nameOrAllowedTypes as TName, allowedTypes, true, true); return out; } @@ -583,7 +584,8 @@ export class SchemaFactory< TreeArrayNode, Iterable>, true, - T + T, + undefined > = this.namedArray(nameOrAllowedTypes as TName, allowedTypes, true, true); return out; } diff --git a/packages/dds/tree/src/test/simple-tree/core/types.spec.ts b/packages/dds/tree/src/test/simple-tree/core/types.spec.ts index 90097e53890e..8a3839bdca3a 100644 --- a/packages/dds/tree/src/test/simple-tree/core/types.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/core/types.spec.ts @@ -136,7 +136,6 @@ describe("simple-tree types", () => { public static readonly identifier = "Subclass"; public static readonly info = numberSchema; public static readonly implicitlyConstructable: false; - public static readonly metadata?: NodeSchemaMetadata = undefined; public static override prepareInstance( this: typeof TreeNodeValid, @@ -237,7 +236,6 @@ describe("simple-tree types", () => { public static readonly info = numberSchema; public static readonly implicitlyConstructable: false; public static readonly childTypes: ReadonlySet = new Set(); - public static readonly metadata?: NodeSchemaMetadata = undefined; public static override buildRawNode( this: typeof TreeNodeValid, @@ -291,7 +289,6 @@ describe("simple-tree types", () => { public static readonly info = numberSchema; public static readonly implicitlyConstructable: false; public static readonly childTypes: ReadonlySet = new Set(); - public static readonly metadata?: NodeSchemaMetadata = undefined; public static override buildRawNode( this: typeof TreeNodeValid, From 594b1d7dd2b38340b73639248027d56c4d4fcd0c Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 00:03:15 +0000 Subject: [PATCH 19/55] remove: Unused import --- packages/dds/tree/src/test/simple-tree/core/types.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/dds/tree/src/test/simple-tree/core/types.spec.ts b/packages/dds/tree/src/test/simple-tree/core/types.spec.ts index 8a3839bdca3a..0ecfc646aaf3 100644 --- a/packages/dds/tree/src/test/simple-tree/core/types.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/core/types.spec.ts @@ -24,7 +24,6 @@ import { typeSchemaSymbol, // Used to test that TreeNode is a type only export. TreeNode as TreeNodePublic, - type NodeSchemaMetadata, } from "../../../simple-tree/index.js"; import type { FlexTreeNode } from "../../../feature-libraries/index.js"; // eslint-disable-next-line import/no-internal-modules From a94f4c281ddc663606f1faaabe6ac86a088641d4 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 00:14:59 +0000 Subject: [PATCH 20/55] refactor(test): Replace withMetadata tests with a single test --- .../simple-tree/api/schemaFactory.spec.ts | 60 ++++++------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 61dbd31d9f65..531200867540 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -364,20 +364,6 @@ describe("schemaFactory", () => { ); }); - it("withMetadata", () => { - const factory = new SchemaFactory(""); - - class Foo extends withMetadata(factory.object("Foo", { bar: factory.number }), { - description: "An object", - custom: { baz: true }, - }) {} - - assert.deepEqual(Foo.metadata, { - description: "An object", - custom: { baz: true }, - }); - }); - it("Field schema metadata", () => { const schemaFactory = new SchemaFactory("com.example"); const barMetadata = { @@ -558,20 +544,6 @@ describe("schemaFactory", () => { class NamedList extends factory.array("name", factory.number) {} const namedInstance = new NamedList([5]); }); - - it("withMetadata", () => { - const factory = new SchemaFactory(""); - - class Foo extends withMetadata(factory.array("Foo", factory.number), { - description: "An array of numbers", - custom: { baz: true }, - }) {} - - assert.deepEqual(Foo.metadata, { - description: "An array of numbers", - custom: { baz: true }, - }); - }); }); describe("Map", () => { @@ -628,20 +600,6 @@ describe("schemaFactory", () => { class NamedMap extends factory.map("name", factory.number) {} const namedInstance = new NamedMap(new Map([["x", 5]])); }); - - it("withMetadata", () => { - const factory = new SchemaFactory(""); - - class Foo extends withMetadata(factory.map("Foo", factory.number), { - description: "A map containing numbers", - custom: { baz: true }, - }) {} - - assert.deepEqual(Foo.metadata, { - description: "A map containing numbers", - custom: { baz: true }, - }); - }); }); describe("produces proxies that can be read after insertion for trees of", () => { @@ -1070,6 +1028,24 @@ describe("schemaFactory", () => { assert.deepEqual(getKeys(arr), [0]); assert.deepEqual(getKeys(mapNode), ["x"]); }); + + it("withMetadata", () => { + const factory = new SchemaFactory(""); + + class Foo extends withMetadata(factory.array("Foo", factory.number), { + description: "An array of numbers", + custom: { baz: true }, + }) {} + + assert.deepEqual(Foo.metadata, { + description: "An array of numbers", + custom: { baz: true }, + }); + + // Ensure the typing is as we expect + assert.equal(Foo.metadata.description, "An array of numbers"); + assert.equal(Foo.metadata.custom.baz, true); + }); }); // kind based narrowing example From 17eca896d6c5402c85a2fda9d4db413071294951 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 00:17:15 +0000 Subject: [PATCH 21/55] improvement: Make metadata properties readonly --- packages/dds/tree/api-report/tree.alpha.api.md | 7 ++++++- packages/dds/tree/api-report/tree.beta.api.md | 7 ++++++- packages/dds/tree/api-report/tree.legacy.alpha.api.md | 7 ++++++- packages/dds/tree/api-report/tree.legacy.public.api.md | 7 ++++++- packages/dds/tree/api-report/tree.public.api.md | 7 ++++++- packages/dds/tree/src/index.ts | 1 + packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts | 3 ++- .../tree/src/test/simple-tree/api/schemaFactory.spec.ts | 8 ++++++++ packages/dds/tree/src/util/utils.ts | 5 ++++- .../api-report/fluid-framework.alpha.api.md | 7 ++++++- .../api-report/fluid-framework.beta.api.md | 7 ++++++- .../api-report/fluid-framework.legacy.alpha.api.md | 7 ++++++- .../api-report/fluid-framework.legacy.public.api.md | 7 ++++++- .../api-report/fluid-framework.public.api.md | 7 ++++++- 14 files changed, 75 insertions(+), 12 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 938893bee236..b5288a0cae5f 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -535,6 +535,11 @@ export type ReadSchema = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -866,7 +871,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index d6375f414c7e..7bf357be8e6a 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -304,6 +304,11 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } +// @public +export type RecursiveReadonly = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -536,7 +541,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index d853288e07aa..1c1ee0ff266f 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -299,6 +299,11 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } +// @public +export type RecursiveReadonly = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -523,7 +528,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index aaaf6c3d7c30..a6b514e452ab 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -299,6 +299,11 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } +// @public +export type RecursiveReadonly = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -520,7 +525,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index aaaf6c3d7c30..a6b514e452ab 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -299,6 +299,11 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } +// @public +export type RecursiveReadonly = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -520,7 +525,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed diff --git a/packages/dds/tree/src/index.ts b/packages/dds/tree/src/index.ts index c90cc0747cb2..fbb347b0963e 100644 --- a/packages/dds/tree/src/index.ts +++ b/packages/dds/tree/src/index.ts @@ -200,6 +200,7 @@ export { type UnionToIntersection, type UnionToTuple, type PopUnion, + type RecursiveReadonly, } from "./util/index.js"; import * as InternalTypes from "./internalTypes.js"; diff --git a/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts b/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts index eda50204ab0a..515592a93e83 100644 --- a/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts +++ b/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. */ +import type { RecursiveReadonly } from "../../util/index.js"; import type { NodeSchemaMetadata, TreeLeafValue } from "../schemaTypes.js"; import type { InternalTreeNode, TreeNode, Unhydrated } from "./types.js"; @@ -272,7 +273,7 @@ export interface TreeNodeSchemaCore< /** * User-provided {@link NodeSchemaMetadata} for this schema. */ - readonly metadata?: TMetadata | undefined; + readonly metadata?: RecursiveReadonly | undefined; /** * Constructs an instance of this node type. diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 531200867540..4d85f7fa7174 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -1045,6 +1045,14 @@ describe("schemaFactory", () => { // Ensure the typing is as we expect assert.equal(Foo.metadata.description, "An array of numbers"); assert.equal(Foo.metadata.custom.baz, true); + + // Ensure properties are readonly + // @ts-expect-error Metadata properties are readonly + Foo.metadata.description = "Foo"; + // @ts-expect-error Metadata properties are readonly + Foo.metadata.custom = {}; + // @ts-expect-error Metadata properties are readonly + Foo.metadata.custom.baz = false; }); }); diff --git a/packages/dds/tree/src/util/utils.ts b/packages/dds/tree/src/util/utils.ts index 8fa6985d136d..48d3db1e7513 100644 --- a/packages/dds/tree/src/util/utils.ts +++ b/packages/dds/tree/src/util/utils.ts @@ -16,7 +16,10 @@ export interface MapGetSet { } /** - * Make all transitive properties in T readonly + * Make all transitive properties in `T` readonly. + * + * @system + * @public */ export type RecursiveReadonly = { readonly [P in keyof T]: RecursiveReadonly; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 2664fa7b2370..7b3e81ed6829 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -892,6 +892,11 @@ export type ReadSchema = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -1250,7 +1255,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index f5c3892ff68c..e3a3352abf22 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -658,6 +658,11 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } +// @public +export type RecursiveReadonly = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -917,7 +922,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index 0ce63a9faa16..aefd6c095808 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -956,6 +956,11 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } +// @public +export type RecursiveReadonly = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -1282,7 +1287,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index f8aa4e32e068..594953c1c057 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -689,6 +689,11 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } +// @public +export type RecursiveReadonly = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -941,7 +946,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index d827a360996b..8b5188b939fb 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -653,6 +653,11 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } +// @public +export type RecursiveReadonly = { + readonly [P in keyof T]: RecursiveReadonly; +}; + // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -901,7 +906,7 @@ export interface TreeNodeSchemaCore | undefined; } // @public @sealed From 65260659ade1de0969dd9e434bc4ece394cd61a0 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 00:19:19 +0000 Subject: [PATCH 22/55] refactor: More consistent typing --- packages/dds/tree/src/simple-tree/schemaTypes.ts | 2 +- .../fluid-framework/api-report/fluid-framework.alpha.api.md | 2 +- .../fluid-framework/api-report/fluid-framework.beta.api.md | 2 +- .../api-report/fluid-framework.legacy.alpha.api.md | 2 +- .../api-report/fluid-framework.legacy.public.api.md | 2 +- .../fluid-framework/api-report/fluid-framework.public.api.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index e8b49753192c..8e0d89db9af3 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -838,7 +838,7 @@ export interface NodeSchemaMetadata { /** * User-defined metadata. */ - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; /** * The description of the Node Schema. diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 7b3e81ed6829..371a5e252eb3 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -835,7 +835,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index e3a3352abf22..ccb71a3f5683 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -621,7 +621,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index aefd6c095808..20476e73ccdf 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -919,7 +919,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index 594953c1c057..af9286c15afc 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -652,7 +652,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index 8b5188b939fb..e45443363fb0 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -616,7 +616,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } From 727857391223e34e365d0ca6797e672e607274d6 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 00:25:38 +0000 Subject: [PATCH 23/55] docs: Add function documentation --- .../tree/src/simple-tree/api/schemaFactory.ts | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index f728380d15e8..2a2c7d43ab2b 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -898,9 +898,25 @@ export function markSchemaMostDerived(schema: TreeNodeSchema): void { } /** - * TODO - * @param nodeSchema - TODO - * @param metadata - TODO + * Binds metadata to a node schema. + * @remarks Accomplishes this by creating a new subclass with the specified metadata, strongly typed. + * + * @param nodeSchema - The node schema to bind metadata to. + * @param metadata - The metadata to bind to the node schema. + * + * @example + * + * ```typescript + * class Point extends withMetadata( + * schemaFactory.object("point", { x: schemaFactory.number, y: schemaFactory.number }), + * { + * description: "A point in 2D space", + * custom: { + * ... // Your custom metadata properties here + * }, + * } + * ) {} + * ``` * * @alpha */ From 465643ba46f3d800ffbcb7219c4ae0d3c7b2e3f0 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 01:04:35 +0000 Subject: [PATCH 24/55] refactor: Stricter typing and remove readonly type modification --- .../dds/tree/api-report/tree.alpha.api.md | 29 ++++++-------- packages/dds/tree/api-report/tree.beta.api.md | 27 ++++++------- .../tree/api-report/tree.legacy.alpha.api.md | 27 ++++++------- .../tree/api-report/tree.legacy.public.api.md | 27 ++++++------- .../dds/tree/api-report/tree.public.api.md | 27 ++++++------- packages/dds/tree/src/index.ts | 1 - .../tree/src/simple-tree/api/schemaFactory.ts | 15 ++++--- .../src/simple-tree/core/treeNodeSchema.ts | 39 ++++++++++++------- .../simple-tree/api/schemaFactory.spec.ts | 31 +++++++-------- packages/dds/tree/src/util/utils.ts | 7 +--- .../api-report/fluid-framework.alpha.api.md | 27 ++++++------- .../api-report/fluid-framework.beta.api.md | 25 +++++------- .../fluid-framework.legacy.alpha.api.md | 25 +++++------- .../fluid-framework.legacy.public.api.md | 25 +++++------- .../api-report/fluid-framework.public.api.md | 25 +++++------- 15 files changed, 157 insertions(+), 200 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index b5288a0cae5f..1e0608ab9a95 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -479,7 +479,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } @@ -535,11 +535,6 @@ export type ReadSchema = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -614,8 +609,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -627,8 +622,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -636,7 +631,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @alpha @@ -846,10 +841,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -862,7 +857,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -871,11 +866,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; @@ -1007,7 +1002,7 @@ export interface ViewContent { } // @alpha -export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: TMetadataOut): TreeNodeSchemaClass; +export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; // @public @sealed export interface WithType { diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index 7bf357be8e6a..8eba9256441b 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -268,7 +268,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } @@ -304,11 +304,6 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } -// @public -export type RecursiveReadonly = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -375,8 +370,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -388,8 +383,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -397,7 +392,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @public @@ -516,10 +511,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -532,7 +527,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -541,11 +536,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index 1c1ee0ff266f..d783a0ba7c4d 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -263,7 +263,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } @@ -299,11 +299,6 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } -// @public -export type RecursiveReadonly = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -370,8 +365,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -383,8 +378,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -392,7 +387,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @public @@ -503,10 +498,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -519,7 +514,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -528,11 +523,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index a6b514e452ab..c6d07450db72 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -263,7 +263,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } @@ -299,11 +299,6 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } -// @public -export type RecursiveReadonly = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -370,8 +365,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -383,8 +378,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -392,7 +387,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @public @@ -500,10 +495,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -516,7 +511,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -525,11 +520,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index a6b514e452ab..c6d07450db72 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -263,7 +263,7 @@ export enum NodeKind { // @public @sealed export interface NodeSchemaMetadata { - readonly custom?: TCustomMetadata; + readonly custom?: TCustomMetadata | undefined; readonly description?: string | undefined; } @@ -299,11 +299,6 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } -// @public -export type RecursiveReadonly = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public @deprecated export type RestrictiveReadonlyRecord = { readonly [P in symbol | string]: P extends K ? T : never; @@ -370,8 +365,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -383,8 +378,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -392,7 +387,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @public @@ -500,10 +495,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -516,7 +511,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -525,11 +520,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/dds/tree/src/index.ts b/packages/dds/tree/src/index.ts index fbb347b0963e..c90cc0747cb2 100644 --- a/packages/dds/tree/src/index.ts +++ b/packages/dds/tree/src/index.ts @@ -200,7 +200,6 @@ export { type UnionToIntersection, type UnionToTuple, type PopUnion, - type RecursiveReadonly, } from "./util/index.js"; import * as InternalTypes from "./internalTypes.js"; diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 2a2c7d43ab2b..2ca9099c5f80 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -921,6 +921,7 @@ export function markSchemaMostDerived(schema: TreeNodeSchema): void { * @alpha */ export function withMetadata< + const TNewCustomMetadata, const TName extends string = string, const TKind extends NodeKind = NodeKind, const TNode extends TreeNode = TreeNode, @@ -928,8 +929,6 @@ export function withMetadata< const ImplicitlyConstructable extends boolean = boolean, const Info = unknown, const TConstructorExtra = never, - const TMetadataIn extends NodeSchemaMetadata = NodeSchemaMetadata, - const TMetadataOut extends TMetadataIn = TMetadataIn, >( nodeSchema: TreeNodeSchemaClass< TName, @@ -938,10 +937,9 @@ export function withMetadata< TInsertable, ImplicitlyConstructable, Info, - TConstructorExtra, - TMetadataIn + TConstructorExtra >, - metadata: TMetadataOut, + metadata: NodeSchemaMetadata, ): TreeNodeSchemaClass< TName, TKind, @@ -950,10 +948,11 @@ export function withMetadata< ImplicitlyConstructable, Info, TConstructorExtra, - TMetadataOut + TNewCustomMetadata > { class Derived extends nodeSchema { - public static readonly metadata?: TMetadataOut | undefined = metadata; + public static readonly metadata?: NodeSchemaMetadata | undefined = + metadata; } return Derived as unknown as TreeNodeSchemaClass< TName, @@ -963,6 +962,6 @@ export function withMetadata< ImplicitlyConstructable, Info, TConstructorExtra, - TMetadataOut + TNewCustomMetadata >; } diff --git a/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts b/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts index 515592a93e83..79ee247a3ab3 100644 --- a/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts +++ b/packages/dds/tree/src/simple-tree/core/treeNodeSchema.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. */ -import type { RecursiveReadonly } from "../../util/index.js"; import type { NodeSchemaMetadata, TreeLeafValue } from "../schemaTypes.js"; import type { InternalTreeNode, TreeNode, Unhydrated } from "./types.js"; @@ -28,7 +27,7 @@ export type TreeNodeSchema< TBuild = never, ImplicitlyConstructable extends boolean = boolean, Info = unknown, - TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, + TCustomMetadata = unknown, > = | (TNode extends TreeNode ? TreeNodeSchemaClass< @@ -39,7 +38,7 @@ export type TreeNodeSchema< ImplicitlyConstructable, Info, never, - TMetadata + TCustomMetadata > : never) | TreeNodeSchemaNonClass< @@ -50,7 +49,7 @@ export type TreeNodeSchema< ImplicitlyConstructable, Info, never, - TMetadata + TCustomMetadata >; /** @@ -69,8 +68,15 @@ export type TreeNodeSchemaNonClass< ImplicitlyConstructable extends boolean = boolean, Info = unknown, TConstructorExtra = never, - TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, -> = TreeNodeSchemaCore & + TCustomMetadata = unknown, +> = TreeNodeSchemaCore< + Name, + Kind, + ImplicitlyConstructable, + Info, + TInsertable, + TCustomMetadata +> & (undefined extends TConstructorExtra ? { /** @@ -140,8 +146,15 @@ export type TreeNodeSchemaClass< ImplicitlyConstructable extends boolean = boolean, Info = unknown, TConstructorExtra = never, - TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, -> = TreeNodeSchemaCore & + TCustomMetadata = unknown, +> = TreeNodeSchemaCore< + Name, + Kind, + ImplicitlyConstructable, + Info, + TInsertable, + TCustomMetadata +> & (undefined extends TConstructorExtra ? { /** @@ -179,7 +192,7 @@ export type TreeNodeSchemaBoth< ImplicitlyConstructable extends boolean = boolean, Info = unknown, TConstructorExtra = never, - TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, + TCustomMetadata = unknown, > = TreeNodeSchemaClass< Name, Kind, @@ -188,7 +201,7 @@ export type TreeNodeSchemaBoth< ImplicitlyConstructable, Info, TConstructorExtra, - TMetadata + TCustomMetadata > & TreeNodeSchemaNonClass< Name, @@ -198,7 +211,7 @@ export type TreeNodeSchemaBoth< ImplicitlyConstructable, Info, TConstructorExtra, - TMetadata + TCustomMetadata >; /** @@ -213,7 +226,7 @@ export interface TreeNodeSchemaCore< out ImplicitlyConstructable extends boolean, out Info = unknown, out TInsertable = never, - out TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, + out TCustomMetadata = unknown, > { /** * Unique (within a document's schema) identifier used to associate nodes with their schema. @@ -273,7 +286,7 @@ export interface TreeNodeSchemaCore< /** * User-provided {@link NodeSchemaMetadata} for this schema. */ - readonly metadata?: RecursiveReadonly | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; /** * Constructs an instance of this node type. diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 4d85f7fa7174..23c3ba167666 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -41,6 +41,7 @@ import { } from "../../../simple-tree/api/schemaFactory.js"; import type { NodeFromSchema, + NodeSchemaMetadata, TreeFieldFromImplicitField, TreeNodeFromImplicitAllowedTypes, // eslint-disable-next-line import/no-internal-modules @@ -1032,27 +1033,25 @@ describe("schemaFactory", () => { it("withMetadata", () => { const factory = new SchemaFactory(""); - class Foo extends withMetadata(factory.array("Foo", factory.number), { - description: "An array of numbers", - custom: { baz: true }, - }) {} + interface CustomMetadata { + baz: boolean; + } - assert.deepEqual(Foo.metadata, { + const fooMetadata: NodeSchemaMetadata = { description: "An array of numbers", - custom: { baz: true }, - }); + custom: { + baz: true, + }, + }; + + class Foo extends withMetadata(factory.array("Foo", factory.number), fooMetadata) {} + + assert.deepEqual(Foo.metadata, fooMetadata); // Ensure the typing is as we expect assert.equal(Foo.metadata.description, "An array of numbers"); - assert.equal(Foo.metadata.custom.baz, true); - - // Ensure properties are readonly - // @ts-expect-error Metadata properties are readonly - Foo.metadata.description = "Foo"; - // @ts-expect-error Metadata properties are readonly - Foo.metadata.custom = {}; - // @ts-expect-error Metadata properties are readonly - Foo.metadata.custom.baz = false; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + assert.equal(Foo.metadata.custom!.baz, true); }); }); diff --git a/packages/dds/tree/src/util/utils.ts b/packages/dds/tree/src/util/utils.ts index 48d3db1e7513..8383dbf2c803 100644 --- a/packages/dds/tree/src/util/utils.ts +++ b/packages/dds/tree/src/util/utils.ts @@ -16,13 +16,10 @@ export interface MapGetSet { } /** - * Make all transitive properties in `T` readonly. - * - * @system - * @public + * Make all transitive properties in `T` readonly */ export type RecursiveReadonly = { - readonly [P in keyof T]: RecursiveReadonly; + +readonly [P in keyof T]: RecursiveReadonly; }; /** diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 371a5e252eb3..8cf1ea4320a0 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -892,11 +892,6 @@ export type ReadSchema = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -976,8 +971,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -989,8 +984,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -998,7 +993,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @alpha @@ -1230,10 +1225,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -1246,7 +1241,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -1255,11 +1250,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; @@ -1391,7 +1386,7 @@ export interface ViewContent { } // @alpha -export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: TMetadataOut): TreeNodeSchemaClass; +export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; // @public @sealed export interface WithType { diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index ccb71a3f5683..000454a77130 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -658,11 +658,6 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } -// @public -export type RecursiveReadonly = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -734,8 +729,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -747,8 +742,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -756,7 +751,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @public @@ -897,10 +892,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -913,7 +908,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -922,11 +917,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index 20476e73ccdf..8d87d208e1d6 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -956,11 +956,6 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } -// @public -export type RecursiveReadonly = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -1032,8 +1027,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -1045,8 +1040,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -1054,7 +1049,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @public @@ -1262,10 +1257,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -1278,7 +1273,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -1287,11 +1282,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index af9286c15afc..9ec074181c8b 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -689,11 +689,6 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } -// @public -export type RecursiveReadonly = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -765,8 +760,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -778,8 +773,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -787,7 +782,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @public @@ -921,10 +916,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -937,7 +932,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -946,11 +941,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index e45443363fb0..dc4284e35235 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -653,11 +653,6 @@ interface ReadonlyMapInlined> { values(): IterableIterator>; } -// @public -export type RecursiveReadonly = { - readonly [P in keyof T]: RecursiveReadonly; -}; - // @public export type ReplaceIEventThisPlaceHolder = L extends any[] ? { [K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K]; @@ -729,8 +724,8 @@ export class SchemaFactory>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; }, false, T, undefined>; - readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, NodeSchemaMetadata>; - readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, NodeSchemaMetadata>; + readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; + readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; @@ -742,8 +737,8 @@ export class SchemaFactory; }, false, T, undefined>; - readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, NodeSchemaMetadata>; - readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, NodeSchemaMetadata>; + readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; + readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -751,7 +746,7 @@ export class SchemaFactory(t: T, props?: Omit, "defaultProvider">): FieldSchema; requiredRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; readonly scope: TScope; - readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, NodeSchemaMetadata>; + readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>; } // @public @@ -881,10 +876,10 @@ export type TreeNodeFromImplicitAllowedTypes> = TSchema extends TreeNodeSchemaUnsafe ? NodeFromSchemaUnsafe : TSchema extends AllowedTypesUnsafe ? NodeFromSchemaUnsafe> : unknown; // @public @sealed -export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; +export type TreeNodeSchema = (TNode extends TreeNode ? TreeNodeSchemaClass : never) | TreeNodeSchemaNonClass; // @public @sealed -export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { new (data?: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; } : { new (data: TInsertable | InternalTreeNode | TConstructorExtra): Unhydrated; @@ -897,7 +892,7 @@ export interface TreeNodeSchemaClassUnsafe { +export interface TreeNodeSchemaCore { readonly childTypes: ReadonlySet; // @sealed createFromInsertable(data: TInsertable): Unhydrated; @@ -906,11 +901,11 @@ export interface TreeNodeSchemaCore | undefined; + readonly metadata?: NodeSchemaMetadata | undefined; } // @public @sealed -export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { +export type TreeNodeSchemaNonClass = TreeNodeSchemaCore & (undefined extends TConstructorExtra ? { create(data?: TInsertable | TConstructorExtra): TNode; } : { create(data: TInsertable | TConstructorExtra): TNode; From d477c9314427af1758f22b50ecd593c425ac4c8b Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 01:17:02 +0000 Subject: [PATCH 25/55] test: Simplify test --- .../dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 23c3ba167666..31d55830b0a0 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -1049,9 +1049,9 @@ describe("schemaFactory", () => { assert.deepEqual(Foo.metadata, fooMetadata); // Ensure the typing is as we expect - assert.equal(Foo.metadata.description, "An array of numbers"); + const description = Foo.metadata.description; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - assert.equal(Foo.metadata.custom!.baz, true); + const baz = Foo.metadata.custom!.baz; }); }); From 6a20d5956ea434839a1fa85f0c83352ac8611239 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 01:17:24 +0000 Subject: [PATCH 26/55] revert: Unwanted change --- packages/dds/tree/src/util/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dds/tree/src/util/utils.ts b/packages/dds/tree/src/util/utils.ts index 8383dbf2c803..0c33dd5b9911 100644 --- a/packages/dds/tree/src/util/utils.ts +++ b/packages/dds/tree/src/util/utils.ts @@ -19,7 +19,7 @@ export interface MapGetSet { * Make all transitive properties in `T` readonly */ export type RecursiveReadonly = { - +readonly [P in keyof T]: RecursiveReadonly; + readonly [P in keyof T]: RecursiveReadonly; }; /** From 901db32288c5799fce803d3ae3648080e098c5d8 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 01:20:25 +0000 Subject: [PATCH 27/55] refactor: Simplify typing --- packages/dds/tree/api-report/tree.alpha.api.md | 2 +- .../tree/src/simple-tree/api/schemaFactory.ts | 16 ++++++++-------- .../test/simple-tree/api/schemaFactory.spec.ts | 9 ++------- .../api-report/fluid-framework.alpha.api.md | 2 +- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 1e0608ab9a95..90a26d80582c 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -1002,7 +1002,7 @@ export interface ViewContent { } // @alpha -export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; +export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; // @public @sealed export interface WithType { diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 2ca9099c5f80..080f7102563c 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -921,14 +921,14 @@ export function markSchemaMostDerived(schema: TreeNodeSchema): void { * @alpha */ export function withMetadata< - const TNewCustomMetadata, - const TName extends string = string, - const TKind extends NodeKind = NodeKind, - const TNode extends TreeNode = TreeNode, - const TInsertable = never, - const ImplicitlyConstructable extends boolean = boolean, - const Info = unknown, - const TConstructorExtra = never, + TName extends string = string, + TKind extends NodeKind = NodeKind, + TNode extends TreeNode = TreeNode, + TInsertable = never, + ImplicitlyConstructable extends boolean = boolean, + Info = unknown, + TConstructorExtra = never, + TNewCustomMetadata = unknown, >( nodeSchema: TreeNodeSchemaClass< TName, diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 31d55830b0a0..321a7fa1defb 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -1033,11 +1033,7 @@ describe("schemaFactory", () => { it("withMetadata", () => { const factory = new SchemaFactory(""); - interface CustomMetadata { - baz: boolean; - } - - const fooMetadata: NodeSchemaMetadata = { + const fooMetadata = { description: "An array of numbers", custom: { baz: true, @@ -1050,8 +1046,7 @@ describe("schemaFactory", () => { // Ensure the typing is as we expect const description = Foo.metadata.description; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const baz = Foo.metadata.custom!.baz; + const baz = Foo.metadata.custom.baz; }); }); diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 8cf1ea4320a0..41f8291d72fa 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -1386,7 +1386,7 @@ export interface ViewContent { } // @alpha -export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; +export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; // @public @sealed export interface WithType { From 2be529df2c747cb165e7f1cb0e6567fe60cbf88c Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 01:20:49 +0000 Subject: [PATCH 28/55] remove: Unused import --- packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 321a7fa1defb..cc53c3007d57 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -41,7 +41,6 @@ import { } from "../../../simple-tree/api/schemaFactory.js"; import type { NodeFromSchema, - NodeSchemaMetadata, TreeFieldFromImplicitField, TreeNodeFromImplicitAllowedTypes, // eslint-disable-next-line import/no-internal-modules From 6a76aa288264ae218e9d8f7089b2b73632dfe44a Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 01:32:09 +0000 Subject: [PATCH 29/55] refactor: Type param ordering --- packages/dds/tree/src/simple-tree/api/schemaFactory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 080f7102563c..b827b127ff79 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -921,6 +921,7 @@ export function markSchemaMostDerived(schema: TreeNodeSchema): void { * @alpha */ export function withMetadata< + TNewCustomMetadata = unknown, TName extends string = string, TKind extends NodeKind = NodeKind, TNode extends TreeNode = TreeNode, @@ -928,7 +929,6 @@ export function withMetadata< ImplicitlyConstructable extends boolean = boolean, Info = unknown, TConstructorExtra = never, - TNewCustomMetadata = unknown, >( nodeSchema: TreeNodeSchemaClass< TName, From aadfddfb5e02eed6189ed59414699ead555b1514 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 01:37:24 +0000 Subject: [PATCH 30/55] docs: Small changeset wording update --- .changeset/grey-triangles-shout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index 20d6f91683cd..d03cebe17f04 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -5,7 +5,7 @@ section: tree --- -Metadata can now be associated with Node Schema +Metadata can be associated with Node Schema Users of TreeView can now specify metadata when creating Node Schema via the experimental (alpha) `withMetadata` function. This metadata may include system-understood properties like `description`. From d67d5c953dfa17b833faab7f15e83be57847225f Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:14:27 +0000 Subject: [PATCH 31/55] docs: Update comment --- .../dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index cc53c3007d57..8fc7f9ba17df 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -1043,7 +1043,7 @@ describe("schemaFactory", () => { assert.deepEqual(Foo.metadata, fooMetadata); - // Ensure the typing is as we expect + // Ensure `Foo.metadata` is typed as we expect, and we can access its fields without casting. const description = Foo.metadata.description; const baz = Foo.metadata.custom.baz; }); From 5c3d75d9a92705aeb54776a47ade2cae0df83aec Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:26:04 +0000 Subject: [PATCH 32/55] docs: Update API reports --- packages/dds/tree/api-report/tree.alpha.api.md | 2 +- .../fluid-framework/api-report/fluid-framework.alpha.api.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 90a26d80582c..398f27c19834 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -1002,7 +1002,7 @@ export interface ViewContent { } // @alpha -export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; +export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; // @public @sealed export interface WithType { diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 41f8291d72fa..65e1ca8d7488 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -1386,7 +1386,7 @@ export interface ViewContent { } // @alpha -export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; +export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; // @public @sealed export interface WithType { From 0d273a070f7d902beed4e1bb44598bc53b65155b Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:26:18 +0000 Subject: [PATCH 33/55] revert: Type signature change --- .../tree/src/simple-tree/objectNodeTypes.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/objectNodeTypes.ts b/packages/dds/tree/src/simple-tree/objectNodeTypes.ts index 10cc93c6a10e..7a776e031889 100644 --- a/packages/dds/tree/src/simple-tree/objectNodeTypes.ts +++ b/packages/dds/tree/src/simple-tree/objectNodeTypes.ts @@ -18,27 +18,27 @@ import type { FieldKey } from "../core/index.js"; * @privateRemarks * This is a candidate for being promoted to the public package API. */ -export type ObjectNodeSchema< +export interface ObjectNodeSchema< TName extends string = string, T extends RestrictiveStringRecord = RestrictiveStringRecord, ImplicitlyConstructable extends boolean = boolean, TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, -> = TreeNodeSchemaClass< - TName, - NodeKind.Object, - TreeObjectNode, - object & InsertableObjectFromSchemaRecord, - ImplicitlyConstructable, - T, - never, - TMetadata -> & { +> extends TreeNodeSchemaClass< + TName, + NodeKind.Object, + TreeObjectNode, + object & InsertableObjectFromSchemaRecord, + ImplicitlyConstructable, + T, + never, + TMetadata + > { /** * From property keys to the associated schema. */ readonly fields: ReadonlyMap; -}; +} /** * Extra data provided on all {@link ObjectNodeSchema} that is not included in the (soon possibly public) ObjectNodeSchema type. From 6e4ea430865aebf22976a9c90d661362ab516131 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:27:35 -0800 Subject: [PATCH 34/55] docs: Update changeset wording Co-authored-by: Alex Villarreal <716334+alexvy86@users.noreply.github.com> --- .changeset/grey-triangles-shout.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index d03cebe17f04..9fee95c53b1c 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -30,7 +30,7 @@ Functionality like the experimental conversion of Tree Schema to [JSON Schema](h In the case of the `description` property, it is mapped directly to the `description` property supported by JSON Schema. Custom, user-defined properties can also be specified. -These properties will not be used by the system by default, but can be used to associate common application-specific properties with Field Schema. +These properties will not be used by the system by default, but can be used to associate common application-specific properties with Node Schema. #### Example @@ -42,7 +42,7 @@ They can leverage schema metadata to decorate types of nodes that should be igno interface AppMetadata { /** - * Whether or not the field should be ignored by search. + * Whether or not nodes of this type should be ignored by search. * @defaultValue `false` */ searchIgnore?: boolean; From 61cbeeacf23d750c96bf113e5819e857087f5452 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:29:31 +0000 Subject: [PATCH 35/55] docs: Update changeset to make potential breaking nature more explicit --- .changeset/grey-triangles-shout.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index 9fee95c53b1c..9487dc6736b9 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -65,6 +65,8 @@ class Point extends withMetadata( Search can then be implemented to look for the appropriate metadata, and leverage it to omit the unwanted position data from search. -**Note:** these changes add the new property "metadata" to the base type from which all node schema derive. +#### Potential for breaking existing code + +These changes add the new property "metadata" to the base type from which all node schema derive. If you have existing node schema subclasses that include a property of this name, there is a chance for potential conflict here that could be breaking. -If you encounter issues here, consider renaming your property. +If you encounter issues here, consider renaming your property or leveraging the new `withMetadata` API. From 93a30e6f958883d8b72c2bc82f905da2fe0742e4 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:39:35 +0000 Subject: [PATCH 36/55] docs: Update wording --- packages/dds/tree/src/simple-tree/schemaTypes.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index 8e0d89db9af3..29949695fbc6 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -192,8 +192,9 @@ export interface FieldProps { * Optional metadata to associate with the field. * * @remarks - * Note: this metadata is not persisted; it is strictly local to the application. - * So, making changes to these values will not affect collaborators. + * Note: this metadata is not persisted nor made part of the collaborative state; it is strictly client-local. + * Different clients in the same collaborative session may see different metadata for the same field. + * For the same reason, an application may change the properties of this metadata without fear of breaking collaboration. */ readonly metadata?: FieldSchemaMetadata; } From 845082a41a783d6b4de6b994f18cd4abc415a9fb Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:40:53 +0000 Subject: [PATCH 37/55] docs: Fix comment --- packages/dds/tree/src/simple-tree/schemaTypes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index 29949695fbc6..680b62789e1e 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -846,7 +846,7 @@ export interface NodeSchemaMetadata { * * @remarks * - * If provided, will be used by the system in scenarios where a description of the field is useful. + * If provided, will be used by the system in scenarios where a description of the kind of node is useful. * E.g., when converting a Node Schema to {@link https://json-schema.org/ | JSON Schema}, this description will be * used as the `description` property. */ From fe46a274ba1b4f7b33415130f590146bf1401bf2 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:44:16 +0000 Subject: [PATCH 38/55] docs: Restore removed test condition, but commented out with an explanation comment --- .../dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts index 011565d1559a..bc5873614b84 100644 --- a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts @@ -156,6 +156,8 @@ describe("getJsonSchema", () => { const validator = getJsonValidator(actual); // Verify expected data validation behavior. + // Array nodes do not satisfy AJV's array validation. This should be uncommented if/when we change this behavior. + // validator(hydrate(Schema, ["Hello", "world"]), true); validator([], true); validator(["Hello", "world"], true); validator("Hello world", false); From ed4fb02c0adf47ee97d62bab403ffee2583fccc3 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 19:17:19 +0000 Subject: [PATCH 39/55] test: Expand test --- .../dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 8fc7f9ba17df..0c0e8d14c93a 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -1046,6 +1046,12 @@ describe("schemaFactory", () => { // Ensure `Foo.metadata` is typed as we expect, and we can access its fields without casting. const description = Foo.metadata.description; const baz = Foo.metadata.custom.baz; + + // Ensure we can construct a node from a schema with metadata. + const constructed = new Foo([42, 37]); + + // Ensure we can hydrate data using a schema with metadata. + const hydrated = hydrate(Foo, [42, 37]); }); }); From 2a9ade4254e88cb831c06201d28e0f8d2a417155 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:23:07 -0800 Subject: [PATCH 40/55] docs: Remove comment --- packages/dds/tree/src/simple-tree/schemaTypes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index 680b62789e1e..aef91429d493 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -194,7 +194,6 @@ export interface FieldProps { * @remarks * Note: this metadata is not persisted nor made part of the collaborative state; it is strictly client-local. * Different clients in the same collaborative session may see different metadata for the same field. - * For the same reason, an application may change the properties of this metadata without fear of breaking collaboration. */ readonly metadata?: FieldSchemaMetadata; } From a294afc90474056fe510085b7dd74e03513d9cc3 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:43:44 -0800 Subject: [PATCH 41/55] docs: Add link to previous release notes in changeset --- .changeset/grey-triangles-shout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index 9487dc6736b9..7cca8f12d227 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -26,7 +26,7 @@ class Point extends withMetadata( ``` -Functionality like the experimental conversion of Tree Schema to [JSON Schema](https://json-schema.org/) (`getJsonSchema`) leverages such system-understood metadata to generate useful information. +Functionality like the experimental conversion of Tree Schema to [JSON Schema](https://json-schema.org/) ([getJsonSchema](https://github.com/microsoft/FluidFramework/releases/tag/client_v2.4.0#user-content-metadata-can-now-be-associated-with-field-schema-22564)) leverages such system-understood metadata to generate useful information. In the case of the `description` property, it is mapped directly to the `description` property supported by JSON Schema. Custom, user-defined properties can also be specified. From af07d78c0c8d496320ea7d1e280d93a83742eb7f Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:19:49 -0800 Subject: [PATCH 42/55] refactor: Required parameter --- packages/dds/tree/src/simple-tree/api/schemaFactory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index b827b127ff79..4a35bca7e623 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -951,7 +951,7 @@ export function withMetadata< TNewCustomMetadata > { class Derived extends nodeSchema { - public static readonly metadata?: NodeSchemaMetadata | undefined = + public static readonly metadata: NodeSchemaMetadata | undefined = metadata; } return Derived as unknown as TreeNodeSchemaClass< From 79c0716cdc6d500ae2e476b3ea016e60c284ed7c Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:06:31 -0800 Subject: [PATCH 43/55] fix(docs): Configure SWA to never emit trailing slashes for website URLs (#23286) Ensures consistent relative file path link behavior by ensuring resolved site URLs never include a trailing slash. See Also makes some small fixes to config files for local development. [AB#25895](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/25895) --- docs/static/staticwebapp.config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/static/staticwebapp.config.json b/docs/static/staticwebapp.config.json index 7857c4b8b40e..7eedf1af8032 100644 --- a/docs/static/staticwebapp.config.json +++ b/docs/static/staticwebapp.config.json @@ -14,5 +14,6 @@ "route": "/404", "statusCode": 404 } - ] + ], + "trailingSlash": "never" } From d4e82320a8862d393db032fbb5694555acff9ece Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:58:46 -0800 Subject: [PATCH 44/55] fix(docs): Better trailing slash omission (#23304) Partial reversion of #23286. SWA's implementation of `"trailingSlash": "never"` is currently flawed. The resulting redirect ends up exposing the underlying SWA URL of the site, rather than our configured front door URL. E.g. `https://fluidframework.com/docs/concepts/signals/` ends up redirecting to `https://salmon-sand-0b7fa7c1e.1.azurestaticapps.net/docs/concepts/signals`. - See https://github.com/Azure/static-web-apps/issues/1036 This PR removes that configuration flag, and instead leverages Docusaurus's [trailingSlash](https://docusaurus.io/docs/api/docusaurus-config#trailingSlash) configuration option to not emit trailing slashes. This required updating a handful of relative URL links to use file path links. The guidance documentation in the README has been updated to offer new guidance around relative links in light of new learnings. [AB#25895](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/25895) --- docs/static/staticwebapp.config.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/static/staticwebapp.config.json b/docs/static/staticwebapp.config.json index 7eedf1af8032..7857c4b8b40e 100644 --- a/docs/static/staticwebapp.config.json +++ b/docs/static/staticwebapp.config.json @@ -14,6 +14,5 @@ "route": "/404", "statusCode": 404 } - ], - "trailingSlash": "never" + ] } From ef4c6d69e3f6f13a56d1f7fbe396649cfdbd4238 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Thu, 12 Dec 2024 22:44:26 +0000 Subject: [PATCH 45/55] refactor: Restore to original API model --- .../dds/tree/api-report/tree.alpha.api.md | 24 ++- packages/dds/tree/api-report/tree.beta.api.md | 21 +- .../tree/api-report/tree.legacy.alpha.api.md | 21 +- .../tree/api-report/tree.legacy.public.api.md | 21 +- .../dds/tree/api-report/tree.public.api.md | 21 +- packages/dds/tree/src/index.ts | 2 +- .../dds/tree/src/simple-tree/api/index.ts | 2 +- .../tree/src/simple-tree/api/schemaFactory.ts | 188 +++++++++--------- .../dds/tree/src/simple-tree/arrayNode.ts | 8 +- packages/dds/tree/src/simple-tree/index.ts | 2 +- packages/dds/tree/src/simple-tree/mapNode.ts | 8 +- .../dds/tree/src/simple-tree/objectNode.ts | 8 +- .../tree/src/simple-tree/objectNodeTypes.ts | 6 +- .../dds/tree/src/simple-tree/schemaTypes.ts | 22 ++ .../simple-tree/api/getJsonSchema.spec.ts | 22 +- .../simple-tree/api/schemaFactory.spec.ts | 87 +++++--- .../api/schemaFactoryRecursive.spec.ts | 45 +++-- 17 files changed, 307 insertions(+), 201 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index 398f27c19834..e33a28993390 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -483,6 +483,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @alpha export const noopValidator: JsonValidator; @@ -605,27 +610,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -1001,9 +1006,6 @@ export interface ViewContent { readonly tree: JsonCompatible; } -// @alpha -export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; - // @public @sealed export interface WithType { // @deprecated diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index 8eba9256441b..d3dc174149c4 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -272,6 +272,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -366,27 +371,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index d783a0ba7c4d..a1d23969df61 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -267,6 +267,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -361,27 +366,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index c6d07450db72..1446d5dfa466 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -267,6 +267,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -361,27 +366,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index c6d07450db72..1446d5dfa466 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -267,6 +267,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -361,27 +366,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/src/index.ts b/packages/dds/tree/src/index.ts index c90cc0747cb2..8138f0096224 100644 --- a/packages/dds/tree/src/index.ts +++ b/packages/dds/tree/src/index.ts @@ -128,7 +128,6 @@ export { type FactoryContentObject, type ReadableField, type ReadSchema, - withMetadata, // test recursive schema for checking that d.ts files handles schema correctly test_RecursiveObject, test_RecursiveObject_base, @@ -176,6 +175,7 @@ export { type TreeBranch, type TreeBranchEvents, asTreeViewAlpha, + type NodeSchemaOptions, type NodeSchemaMetadata, } from "./simple-tree/index.js"; export { diff --git a/packages/dds/tree/src/simple-tree/api/index.ts b/packages/dds/tree/src/simple-tree/api/index.ts index c8718c885b7b..83fda6bf3356 100644 --- a/packages/dds/tree/src/simple-tree/api/index.ts +++ b/packages/dds/tree/src/simple-tree/api/index.ts @@ -17,7 +17,7 @@ export { type TreeBranchEvents, asTreeViewAlpha, } from "./tree.js"; -export { SchemaFactory, type ScopedSchemaName, withMetadata } from "./schemaFactory.js"; +export { SchemaFactory, type ScopedSchemaName } from "./schemaFactory.js"; export type { ValidateRecursiveSchema, FixRecursiveArraySchema, diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 4a35bca7e623..abf832073ec0 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -38,6 +38,7 @@ import { type DefaultProvider, getDefaultProvider, type NodeSchemaMetadata, + type NodeSchemaOptions, } from "../schemaTypes.js"; import { inPrototypeChain } from "../core/index.js"; import type { @@ -47,7 +48,6 @@ import type { TreeNodeSchemaClass, TreeNodeSchemaNonClass, TreeNodeSchemaBoth, - TreeNode, } from "../core/index.js"; import { type TreeArrayNode, arraySchema } from "../arrayNode.js"; import { @@ -324,18 +324,22 @@ export class SchemaFactory< public object< const Name extends TName, const T extends RestrictiveStringRecord, + const TCustomMetadata = unknown, >( name: Name, fields: T, + options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, - T + T, + never, + TCustomMetadata > { - return objectSchema(this.scoped(name), fields, true); + return objectSchema(this.scoped(name), fields, true, options?.metadata); } /** @@ -383,9 +387,14 @@ export class SchemaFactory< * class NamedMap extends factory.map("name", factory.number) {} * ``` */ - public map( + public map< + Name extends TName, + const T extends ImplicitAllowedTypes, + const TCustomMetadata = unknown, + >( name: Name, allowedTypes: T, + options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Map, @@ -393,7 +402,8 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined + undefined, + TCustomMetadata >; /** @@ -404,9 +414,10 @@ export class SchemaFactory< * This seems like a TypeScript bug getting variance backwards for overload return types since it's erroring when the relation between the overload * and the implementation is type safe, and forcing an unsafe typing instead. */ - public map( + public map( nameOrAllowedTypes: TName | ((T & TreeNodeSchema) | readonly TreeNodeSchema[]), allowedTypes?: T, + options?: NodeSchemaOptions, ): TreeNodeSchema, MapNodeInsertableData, true, T> { if (allowedTypes === undefined) { const types = nameOrAllowedTypes as (T & TreeNodeSchema) | readonly TreeNodeSchema[]; @@ -420,6 +431,7 @@ export class SchemaFactory< nameOrAllowedTypes as T, false, true, + options?.metadata, ) as TreeNodeSchema, ) as TreeNodeSchemaBoth< string, @@ -428,10 +440,11 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined + undefined, + TCustomMetadata >; } - // To actually have type safety, assign to the type this method should return before implicitly up-casting when returning. + // To actually have type safety, assign to the type this method should return before implicitly upcasting when returning. const out: TreeNodeSchemaBoth< string, NodeKind.Map, @@ -439,8 +452,15 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined - > = this.namedMap(nameOrAllowedTypes as TName, allowedTypes, true, true); + undefined, + TCustomMetadata + > = this.namedMap( + nameOrAllowedTypes as TName, + allowedTypes, + true, + true, + options?.metadata, + ); return out; } @@ -453,11 +473,13 @@ export class SchemaFactory< Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, + TCustomMetadata = unknown, >( name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable, + metadata: NodeSchemaMetadata | undefined, ): TreeNodeSchemaBoth< ScopedSchemaName, NodeKind.Map, @@ -465,7 +487,8 @@ export class SchemaFactory< MapNodeInsertableData, ImplicitlyConstructable, T, - undefined + undefined, + TCustomMetadata > { return mapSchema( this.scoped(name), @@ -473,6 +496,7 @@ export class SchemaFactory< implicitlyConstructable, // The current policy is customizable nodes don't get fake prototypes. !customizable, + metadata, ); } @@ -533,9 +557,14 @@ export class SchemaFactory< * * {@label NAMED} */ - public array( + public array< + const Name extends TName, + const T extends ImplicitAllowedTypes, + const TCustomMetadata = unknown, + >( name: Name, allowedTypes: T, + options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Array, @@ -543,7 +572,8 @@ export class SchemaFactory< Iterable>, true, T, - undefined + undefined, + TCustomMetadata >; /** @@ -552,22 +582,24 @@ export class SchemaFactory< * @privateRemarks * This should return TreeNodeSchemaBoth: see note on "map" implementation for details. */ - public array( + public array( nameOrAllowedTypes: TName | ((T & TreeNodeSchema) | readonly TreeNodeSchema[]), allowedTypes?: T, + options?: NodeSchemaOptions, ): TreeNodeSchema< ScopedSchemaName, NodeKind.Array, TreeArrayNode, Iterable>, true, - T + T, + TCustomMetadata > { if (allowedTypes === undefined) { const types = nameOrAllowedTypes as (T & TreeNodeSchema) | readonly TreeNodeSchema[]; const fullName = structuralName("Array", types); return getOrCreate(this.structuralTypes, fullName, () => - this.namedArray(fullName, nameOrAllowedTypes as T, false, true), + this.namedArray(fullName, nameOrAllowedTypes as T, false, true, options?.metadata), ) as TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Array, @@ -575,7 +607,8 @@ export class SchemaFactory< Iterable>, true, T, - undefined + undefined, + TCustomMetadata >; } const out: TreeNodeSchemaBoth< @@ -585,8 +618,15 @@ export class SchemaFactory< Iterable>, true, T, - undefined - > = this.namedArray(nameOrAllowedTypes as TName, allowedTypes, true, true); + undefined, + TCustomMetadata + > = this.namedArray( + nameOrAllowedTypes as TName, + allowedTypes, + true, + true, + options?.metadata, + ); return out; } @@ -603,11 +643,13 @@ export class SchemaFactory< Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, + const TCustomMetadata = unknown, >( name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable, + metadata: NodeSchemaMetadata | undefined, ): TreeNodeSchemaBoth< ScopedSchemaName, NodeKind.Array, @@ -615,9 +657,16 @@ export class SchemaFactory< Iterable>, ImplicitlyConstructable, T, - undefined + undefined, + TCustomMetadata > { - return arraySchema(this.scoped(name), allowedTypes, implicitlyConstructable, customizable); + return arraySchema( + this.scoped(name), + allowedTypes, + implicitlyConstructable, + customizable, + metadata, + ); } /** @@ -736,18 +785,22 @@ export class SchemaFactory< public objectRecursive< const Name extends TName, const T extends Unenforced>, - >(name: Name, t: T) { + const TCustomMetadata = unknown, + >(name: Name, t: T, options?: NodeSchemaOptions) { type TScopedName = ScopedSchemaName; return this.object( name, t as T & RestrictiveStringRecord, + options, ) as unknown as TreeNodeSchemaClass< TScopedName, NodeKind.Object, TreeObjectNodeUnsafe, object & InsertableObjectFromSchemaRecordUnsafe, false, - T + T, + never, + TCustomMetadata >; } @@ -762,12 +815,14 @@ export class SchemaFactory< public arrayRecursive< const Name extends TName, const T extends Unenforced, - >(name: Name, allowedTypes: T) { + const TCustomMetadata = unknown, + >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { const RecursiveArray = this.namedArray( name, allowedTypes as T & ImplicitAllowedTypes, true, false, + options?.metadata, ); return RecursiveArray as TreeNodeSchemaClass< @@ -790,7 +845,8 @@ export class SchemaFactory< }, false, T, - undefined + undefined, + TCustomMetadata >; } @@ -802,10 +858,11 @@ export class SchemaFactory< * See {@link ValidateRecursiveSchema} for additional information about using recursive schema. */ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - public mapRecursive>( - name: Name, - allowedTypes: T, - ) { + public mapRecursive< + Name extends TName, + const T extends Unenforced, + const TCustomMetadata = unknown, + >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { const MapSchema = this.namedMap( name, allowedTypes as T & ImplicitAllowedTypes, @@ -813,6 +870,7 @@ export class SchemaFactory< // Setting this (implicitlyConstructable) to true seems to work ok currently, but not for other node kinds. // Supporting this could be fragile and might break other future changes, so it's being kept as false for now. false, + options?.metadata, ); return MapSchema as TreeNodeSchemaClass< @@ -844,7 +902,8 @@ export class SchemaFactory< }, false, T, - undefined + undefined, + TCustomMetadata >; } } @@ -896,72 +955,3 @@ export function markSchemaMostDerived(schema: TreeNodeSchema): void { (schema as typeof TreeNodeValid & TreeNodeSchema).markMostDerived(); } - -/** - * Binds metadata to a node schema. - * @remarks Accomplishes this by creating a new subclass with the specified metadata, strongly typed. - * - * @param nodeSchema - The node schema to bind metadata to. - * @param metadata - The metadata to bind to the node schema. - * - * @example - * - * ```typescript - * class Point extends withMetadata( - * schemaFactory.object("point", { x: schemaFactory.number, y: schemaFactory.number }), - * { - * description: "A point in 2D space", - * custom: { - * ... // Your custom metadata properties here - * }, - * } - * ) {} - * ``` - * - * @alpha - */ -export function withMetadata< - TNewCustomMetadata = unknown, - TName extends string = string, - TKind extends NodeKind = NodeKind, - TNode extends TreeNode = TreeNode, - TInsertable = never, - ImplicitlyConstructable extends boolean = boolean, - Info = unknown, - TConstructorExtra = never, ->( - nodeSchema: TreeNodeSchemaClass< - TName, - TKind, - TNode, - TInsertable, - ImplicitlyConstructable, - Info, - TConstructorExtra - >, - metadata: NodeSchemaMetadata, -): TreeNodeSchemaClass< - TName, - TKind, - TNode, - TInsertable, - ImplicitlyConstructable, - Info, - TConstructorExtra, - TNewCustomMetadata -> { - class Derived extends nodeSchema { - public static readonly metadata: NodeSchemaMetadata | undefined = - metadata; - } - return Derived as unknown as TreeNodeSchemaClass< - TName, - TKind, - TNode, - TInsertable, - ImplicitlyConstructable, - Info, - TConstructorExtra, - TNewCustomMetadata - >; -} diff --git a/packages/dds/tree/src/simple-tree/arrayNode.ts b/packages/dds/tree/src/simple-tree/arrayNode.ts index 01b9e1108732..34d90aca5f22 100644 --- a/packages/dds/tree/src/simple-tree/arrayNode.ts +++ b/packages/dds/tree/src/simple-tree/arrayNode.ts @@ -18,6 +18,7 @@ import { normalizeAllowedTypes, type ImplicitAllowedTypes, type InsertableTreeNodeFromImplicitAllowedTypes, + type NodeSchemaMetadata, type TreeLeafValue, type TreeNodeFromImplicitAllowedTypes, } from "./schemaTypes.js"; @@ -1062,11 +1063,13 @@ export function arraySchema< TName extends string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, + const TCustomMetadata = unknown, >( identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, customizable: boolean, + metadata?: NodeSchemaMetadata, ) { type Output = TreeNodeSchemaBoth< TName, @@ -1075,7 +1078,8 @@ export function arraySchema< Iterable>, ImplicitlyConstructable, T, - undefined + undefined, + TCustomMetadata >; const lazyChildTypes = new Lazy(() => normalizeAllowedTypes(info)); @@ -1157,6 +1161,8 @@ export function arraySchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } + public static readonly metadata: NodeSchemaMetadata | undefined = + metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/simple-tree/index.ts b/packages/dds/tree/src/simple-tree/index.ts index c7766d9ce446..35e73ca947a9 100644 --- a/packages/dds/tree/src/simple-tree/index.ts +++ b/packages/dds/tree/src/simple-tree/index.ts @@ -122,7 +122,6 @@ export { type CustomTreeNode, type CustomTreeValue, tryStoredSchemaAsArray, - withMetadata, } from "./api/index.js"; export { type NodeFromSchema, @@ -155,6 +154,7 @@ export { type Input, type ReadableField, type ReadSchema, + type NodeSchemaOptions, type NodeSchemaMetadata, } from "./schemaTypes.js"; export { diff --git a/packages/dds/tree/src/simple-tree/mapNode.ts b/packages/dds/tree/src/simple-tree/mapNode.ts index f43a0c15a9a9..1ccfe6187bf1 100644 --- a/packages/dds/tree/src/simple-tree/mapNode.ts +++ b/packages/dds/tree/src/simple-tree/mapNode.ts @@ -17,6 +17,7 @@ import { normalizeAllowedTypes, type ImplicitAllowedTypes, type InsertableTreeNodeFromImplicitAllowedTypes, + type NodeSchemaMetadata, type TreeNodeFromImplicitAllowedTypes, } from "./schemaTypes.js"; import { @@ -235,11 +236,13 @@ export function mapSchema< TName extends string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, + const TCustomMetadata = unknown, >( identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, useMapPrototype: boolean, + metadata?: NodeSchemaMetadata, ) { const lazyChildTypes = new Lazy(() => normalizeAllowedTypes(info)); @@ -283,6 +286,8 @@ export function mapSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } + public static readonly metadata: NodeSchemaMetadata | undefined = + metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { @@ -299,7 +304,8 @@ export function mapSchema< MapNodeInsertableData, ImplicitlyConstructable, T, - undefined + undefined, + TCustomMetadata > = Schema; return schemaErased; } diff --git a/packages/dds/tree/src/simple-tree/objectNode.ts b/packages/dds/tree/src/simple-tree/objectNode.ts index 5d692dc6d13a..0bb6aae7233f 100644 --- a/packages/dds/tree/src/simple-tree/objectNode.ts +++ b/packages/dds/tree/src/simple-tree/objectNode.ts @@ -26,6 +26,7 @@ import { normalizeFieldSchema, type ImplicitAllowedTypes, FieldKind, + type NodeSchemaMetadata, } from "./schemaTypes.js"; import { type TreeNodeSchema, @@ -326,11 +327,14 @@ export function objectSchema< TName extends string, const T extends RestrictiveStringRecord, const ImplicitlyConstructable extends boolean, + const TCustomMetadata = unknown, >( identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, -): ObjectNodeSchema & ObjectNodeSchemaInternalData { + metadata?: NodeSchemaMetadata, +): ObjectNodeSchema & + ObjectNodeSchemaInternalData { // Ensure no collisions between final set of property keys, and final set of stored keys (including those // implicitly derived from property keys) assertUniqueKeys(identifier, info); @@ -454,6 +458,8 @@ export function objectSchema< public static get childTypes(): ReadonlySet { return lazyChildTypes.value; } + public static readonly metadata: NodeSchemaMetadata | undefined = + metadata; // eslint-disable-next-line import/no-deprecated public get [typeNameSymbol](): TName { diff --git a/packages/dds/tree/src/simple-tree/objectNodeTypes.ts b/packages/dds/tree/src/simple-tree/objectNodeTypes.ts index 7a776e031889..789de1cfdd74 100644 --- a/packages/dds/tree/src/simple-tree/objectNodeTypes.ts +++ b/packages/dds/tree/src/simple-tree/objectNodeTypes.ts @@ -9,7 +9,7 @@ import type { InsertableObjectFromSchemaRecord, SimpleKeyMap, } from "./objectNode.js"; -import type { ImplicitFieldSchema, FieldSchema, NodeSchemaMetadata } from "./schemaTypes.js"; +import type { ImplicitFieldSchema, FieldSchema } from "./schemaTypes.js"; import { NodeKind, type TreeNodeSchemaClass, type TreeNodeSchema } from "./core/index.js"; import type { FieldKey } from "../core/index.js"; @@ -23,7 +23,7 @@ export interface ObjectNodeSchema< T extends RestrictiveStringRecord = RestrictiveStringRecord, ImplicitlyConstructable extends boolean = boolean, - TMetadata extends NodeSchemaMetadata = NodeSchemaMetadata, + TCustomMetadata = unknown, > extends TreeNodeSchemaClass< TName, NodeKind.Object, @@ -32,7 +32,7 @@ export interface ObjectNodeSchema< ImplicitlyConstructable, T, never, - TMetadata + TCustomMetadata > { /** * From property keys to the associated schema. diff --git a/packages/dds/tree/src/simple-tree/schemaTypes.ts b/packages/dds/tree/src/simple-tree/schemaTypes.ts index aef91429d493..5baea3ed98b3 100644 --- a/packages/dds/tree/src/simple-tree/schemaTypes.ts +++ b/packages/dds/tree/src/simple-tree/schemaTypes.ts @@ -828,9 +828,31 @@ export type NodeBuilderData { + /** + * Optional metadata to associate with the Node Schema. + * + * @remarks + * Note: this metadata is not persisted nor made part of the collaborative state; it is strictly client-local. + * Different clients in the same collaborative session may see different metadata for the same field. + */ + readonly metadata?: NodeSchemaMetadata | undefined; +} + /** * Metadata associated with a Node Schema. * + * @remarks Specified via {@link NodeSchemaOptions.metadata}. + * * @sealed * @public */ diff --git a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts index bc5873614b84..208a01e5503c 100644 --- a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts @@ -9,7 +9,6 @@ import { NodeKind, SchemaFactory, type JsonTreeSchema, - withMetadata, } from "../../../simple-tree/index.js"; import { hydrate } from "../utils.js"; @@ -127,8 +126,10 @@ describe("getJsonSchema", () => { it("Array schema", () => { const schemaFactory = new SchemaFactory("test"); - const Schema = withMetadata(schemaFactory.array("array", schemaFactory.string), { - description: "An array of strings", + const Schema = schemaFactory.array("array", schemaFactory.string, { + metadata: { + description: "An array of strings", + }, }); const actual = getJsonSchema(Schema); @@ -168,8 +169,10 @@ describe("getJsonSchema", () => { it("Map schema", () => { const schemaFactory = new SchemaFactory("test"); - const Schema = withMetadata(schemaFactory.map("map", schemaFactory.string), { - description: "A map containing strings", + const Schema = schemaFactory.map("map", schemaFactory.string, { + metadata: { + description: "A map containing strings", + }, }); const actual = getJsonSchema(Schema); @@ -228,16 +231,17 @@ describe("getJsonSchema", () => { it("Object schema", () => { const schemaFactory = new SchemaFactory("test"); - const Schema = withMetadata( - schemaFactory.object("object", { + const Schema = schemaFactory.object( + "object", + { foo: schemaFactory.optional(schemaFactory.number, { metadata: { description: "A number representing the concept of Foo." }, }), bar: schemaFactory.required(schemaFactory.string, { metadata: { description: "A string representing the concept of Bar." }, }), - }), - { description: "An object with Foo and Bar." }, + }, + { metadata: { description: "An object with Foo and Bar." } }, ); const actual = getJsonSchema(Schema); diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 0c0e8d14c93a..d00ba7025f4b 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -36,7 +36,6 @@ import type { ObjectNodeSchema } from "../../../simple-tree/objectNodeTypes.js"; import { SchemaFactory, schemaFromValue, - withMetadata, // eslint-disable-next-line import/no-internal-modules } from "../../../simple-tree/api/schemaFactory.js"; import type { @@ -364,6 +363,29 @@ describe("schemaFactory", () => { ); }); + it("Node schema metadata", () => { + const factory = new SchemaFactory(""); + + const fooMetadata = { + description: "An object called Foo", + custom: { + baz: true, + }, + }; + + class Foo extends factory.object( + "Foo", + { bar: factory.number }, + { metadata: fooMetadata }, + ) {} + + assert.deepEqual(Foo.metadata, fooMetadata); + + // Ensure `Foo.metadata` is typed as we expect, and we can access its fields without casting. + const description = Foo.metadata.description; + const baz = Foo.metadata.custom.baz; + }); + it("Field schema metadata", () => { const schemaFactory = new SchemaFactory("com.example"); const barMetadata = { @@ -544,6 +566,25 @@ describe("schemaFactory", () => { class NamedList extends factory.array("name", factory.number) {} const namedInstance = new NamedList([5]); }); + + it("Node schema metadata", () => { + const factory = new SchemaFactory(""); + + const fooMetadata = { + description: "An array of numbers", + custom: { + baz: true, + }, + }; + + class Foo extends factory.array("Foo", factory.number, { metadata: fooMetadata }) {} + + assert.deepEqual(Foo.metadata, fooMetadata); + + // Ensure `Foo.metadata` is typed as we expect, and we can access its fields without casting. + const description = Foo.metadata.description; + const baz = Foo.metadata.custom.baz; + }); }); describe("Map", () => { @@ -600,6 +641,25 @@ describe("schemaFactory", () => { class NamedMap extends factory.map("name", factory.number) {} const namedInstance = new NamedMap(new Map([["x", 5]])); }); + + it("Node schema metadata", () => { + const factory = new SchemaFactory(""); + + const fooMetadata = { + description: "A map of numbers", + custom: { + baz: true, + }, + }; + + class Foo extends factory.map("Foo", factory.number, { metadata: fooMetadata }) {} + + assert.deepEqual(Foo.metadata, fooMetadata); + + // Ensure `Foo.metadata` is typed as we expect, and we can access its fields without casting. + const description = Foo.metadata.description; + const baz = Foo.metadata.custom.baz; + }); }); describe("produces proxies that can be read after insertion for trees of", () => { @@ -1028,31 +1088,6 @@ describe("schemaFactory", () => { assert.deepEqual(getKeys(arr), [0]); assert.deepEqual(getKeys(mapNode), ["x"]); }); - - it("withMetadata", () => { - const factory = new SchemaFactory(""); - - const fooMetadata = { - description: "An array of numbers", - custom: { - baz: true, - }, - }; - - class Foo extends withMetadata(factory.array("Foo", factory.number), fooMetadata) {} - - assert.deepEqual(Foo.metadata, fooMetadata); - - // Ensure `Foo.metadata` is typed as we expect, and we can access its fields without casting. - const description = Foo.metadata.description; - const baz = Foo.metadata.custom.baz; - - // Ensure we can construct a node from a schema with metadata. - const constructed = new Foo([42, 37]); - - // Ensure we can hydrate data using a schema with metadata. - const hydrated = hydrate(Foo, [42, 37]); - }); }); // kind based narrowing example diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts index 3e39c5854bf1..27d01417ce5e 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts @@ -22,7 +22,6 @@ import { type FlexListToUnion, type ApplyKindInput, type NodeBuilderData, - withMetadata, } from "../../../simple-tree/index.js"; import type { ValidateRecursiveSchema, @@ -461,14 +460,26 @@ describe("SchemaFactory Recursive methods", () => { it("Node schema metadata", () => { const factory = new SchemaFactory(""); - class Foo extends withMetadata(factory.objectRecursive("Foo", { bar: () => Bar }), { - description: "A recursive object called Foo", - custom: { baz: true }, - }) {} - class Bar extends withMetadata(factory.objectRecursive("Bar", { foo: () => Foo }), { - description: "A recursive object called Bar", - custom: { baz: false }, - }) {} + class Foo extends factory.objectRecursive( + "Foo", + { bar: () => Bar }, + { + metadata: { + description: "A recursive object called Foo", + custom: { baz: true }, + }, + }, + ) {} + class Bar extends factory.objectRecursive( + "Bar", + { foo: () => Foo }, + { + metadata: { + description: "A recursive object called Bar", + custom: { baz: false }, + }, + }, + ) {} assert.deepEqual(Foo.metadata, { description: "A recursive object called Foo", @@ -607,9 +618,11 @@ describe("SchemaFactory Recursive methods", () => { class Foo extends factory.objectRecursive("Foo", { fooList: sf.arrayRecursive("FooList", [() => Foo]), }) {} - class FooList extends withMetadata(factory.arrayRecursive("FooList", [() => Foo]), { - description: "A recursive list", - custom: { baz: true }, + class FooList extends factory.arrayRecursive("FooList", [() => Foo], { + metadata: { + description: "A recursive list", + custom: { baz: true }, + }, }) {} assert.deepEqual(FooList.metadata, { @@ -671,9 +684,11 @@ describe("SchemaFactory Recursive methods", () => { class Foo extends factory.objectRecursive("Foo", { fooList: sf.arrayRecursive("FooList", [() => Foo]), }) {} - class FooList extends withMetadata(factory.mapRecursive("FooList", [() => Foo]), { - description: "A recursive map", - custom: { baz: true }, + class FooList extends factory.mapRecursive("FooList", [() => Foo], { + metadata: { + description: "A recursive map", + custom: { baz: true }, + }, }) {} assert.deepEqual(FooList.metadata, { From 2ddb09ed19bce2d28f8d9ecbcb4c81086cb83be2 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Thu, 12 Dec 2024 22:45:04 +0000 Subject: [PATCH 46/55] docs: Update API reports --- .../api-report/fluid-framework.alpha.api.md | 24 ++++++++++--------- .../api-report/fluid-framework.beta.api.md | 21 +++++++++------- .../fluid-framework.legacy.alpha.api.md | 21 +++++++++------- .../fluid-framework.legacy.public.api.md | 21 +++++++++------- .../api-report/fluid-framework.public.api.md | 21 +++++++++------- 5 files changed, 65 insertions(+), 43 deletions(-) diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 65e1ca8d7488..dd8a87cb8052 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -839,6 +839,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @alpha export const noopValidator: JsonValidator; @@ -967,27 +972,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; @@ -1385,9 +1390,6 @@ export interface ViewContent { readonly tree: JsonCompatible; } -// @alpha -export function withMetadata(nodeSchema: TreeNodeSchemaClass, metadata: NodeSchemaMetadata): TreeNodeSchemaClass; - // @public @sealed export interface WithType { // @deprecated diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index 000454a77130..88d8c63168c9 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -625,6 +625,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -725,27 +730,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index 8d87d208e1d6..d569845bbde0 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -923,6 +923,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -1023,27 +1028,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index 9ec074181c8b..9834a9c7a67c 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -656,6 +656,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -756,27 +761,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index dc4284e35235..05f630b1e527 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -620,6 +620,11 @@ export interface NodeSchemaMetadata { readonly description?: string | undefined; } +// @public @sealed +export interface NodeSchemaOptions { + readonly metadata?: NodeSchemaMetadata | undefined; +} + // @public type ObjectFromSchemaRecord> = { -readonly [Property in keyof T]: Property extends string ? TreeFieldFromImplicitField : unknown; @@ -720,27 +725,27 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; - arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined>; + }, false, T, undefined, TCustomMetadata>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; - objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T>; + object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; + objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & { readonly [Property in keyof T as FieldHasDefaultUnsafe extends false ? Property : never]: InsertableTreeFieldFromImplicitFieldUnsafe>; } & { readonly [Property_1 in keyof T as FieldHasDefaultUnsafe extends true ? Property_1 : never]?: InsertableTreeFieldFromImplicitFieldUnsafe> | undefined; }, false, T, never, TCustomMetadata>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; From 9d5812303cecc198c3fb2df946d23d84c6d8ab55 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Thu, 12 Dec 2024 23:42:31 +0000 Subject: [PATCH 47/55] docs: Update changeset --- .changeset/grey-triangles-shout.md | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index 7cca8f12d227..419386235234 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -7,22 +7,22 @@ section: tree Metadata can be associated with Node Schema -Users of TreeView can now specify metadata when creating Node Schema via the experimental (alpha) `withMetadata` function. +Users of TreeView can now specify metadata when creating Node Schema. This metadata may include system-understood properties like `description`. Example: ```typescript -class Point extends withMetadata( - schemaFactory.object("Point", { - x: schemaFactory.required(schemaFactory.number), - y: schemaFactory.required(schemaFactory.number), - }), - { +class Point extends schemaFactory.object("Point", { + x: schemaFactory.required(schemaFactory.number), + y: schemaFactory.required(schemaFactory.number), +}, +{ + metadata: { description: "A point in 2D space", }, -) {} +}) {} ``` @@ -48,18 +48,18 @@ interface AppMetadata { searchIgnore?: boolean; } -class Point extends withMetadata( - schemaFactory.object("Point", { - x: schemaFactory.required(schemaFactory.number), - y: schemaFactory.required(schemaFactory.number), - }), - { +class Point extends schemaFactory.object("Point", { + x: schemaFactory.required(schemaFactory.number), + y: schemaFactory.required(schemaFactory.number), +}, +{ + metadata: { description: "A point in 2D space", custom: { searchIgnore: true, }, - }, -) {} + } +}) {} ``` @@ -69,4 +69,4 @@ Search can then be implemented to look for the appropriate metadata, and leverag These changes add the new property "metadata" to the base type from which all node schema derive. If you have existing node schema subclasses that include a property of this name, there is a chance for potential conflict here that could be breaking. -If you encounter issues here, consider renaming your property or leveraging the new `withMetadata` API. +If you encounter issues here, consider renaming your property or leveraging the new metadata support. From 71f4d8e351d50638007e2684b928ba7bd97dae18 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:01:25 +0000 Subject: [PATCH 48/55] refactor: Move metadata support for Object nodes down to alpha factory --- .../dds/tree/api-report/tree.alpha.api.md | 4 +-- packages/dds/tree/api-report/tree.beta.api.md | 4 +-- .../tree/api-report/tree.legacy.alpha.api.md | 4 +-- .../tree/api-report/tree.legacy.public.api.md | 4 +-- .../dds/tree/api-report/tree.public.api.md | 4 +-- .../tree/src/simple-tree/api/schemaFactory.ts | 26 +++++-------------- .../src/simple-tree/api/schemaFactoryAlpha.ts | 1 + .../simple-tree/api/getJsonSchema.spec.ts | 3 ++- .../simple-tree/api/schemaFactory.spec.ts | 3 ++- .../api/schemaFactoryRecursive.spec.ts | 3 ++- .../api-report/fluid-framework.alpha.api.md | 4 +-- .../api-report/fluid-framework.beta.api.md | 4 +-- .../fluid-framework.legacy.alpha.api.md | 4 +-- .../fluid-framework.legacy.public.api.md | 4 +-- .../api-report/fluid-framework.public.api.md | 4 +-- 15 files changed, 34 insertions(+), 42 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index ee3d744f9b53..c645d90e731a 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -629,8 +629,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index a5ff43220565..7323447b2787 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -390,8 +390,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index 7f738883e5e9..2c46bfd3e5ee 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -385,8 +385,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index 2093931883be..a8401d0a5eb9 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -385,8 +385,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index 2093931883be..a8401d0a5eb9 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -385,8 +385,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 0287f71d30d7..947e6a6d3ebc 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -155,11 +155,10 @@ export interface SchemaFactoryObjectOptions allowUnknownOptionalFields?: boolean; } -export const defaultSchemaFactoryObjectOptions: Required< - Omit -> = { +export const defaultSchemaFactoryObjectOptions = { allowUnknownOptionalFields: false, -}; + metadata: undefined, +} satisfies SchemaFactoryObjectOptions; /** * The name of a schema produced by {@link SchemaFactory}, including its optional scope prefix. @@ -386,27 +385,23 @@ export class SchemaFactory< public object< const Name extends TName, const T extends RestrictiveStringRecord, - const TCustomMetadata = unknown, >( name: Name, fields: T, - options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, - T, - never, - TCustomMetadata + T > { return objectSchema( this.scoped(name), fields, true, defaultSchemaFactoryObjectOptions.allowUnknownOptionalFields, - options?.metadata, + defaultSchemaFactoryObjectOptions.metadata, ); } @@ -852,35 +847,28 @@ export class SchemaFactory< public objectRecursive< const Name extends TName, const T extends Unenforced>, - const TCustomMetadata = unknown, >( name: Name, t: T, - options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, - T, - never, - TCustomMetadata + T > { type TScopedName = ScopedSchemaName; return this.object( name, t as T & RestrictiveStringRecord, - options, ) as unknown as TreeNodeSchemaClass< TScopedName, NodeKind.Object, TreeObjectNodeUnsafe, object & InsertableObjectFromSchemaRecordUnsafe, false, - T, - never, - TCustomMetadata + T >; } diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts b/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts index b8d7abb95f12..071f04108e2c 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts @@ -69,6 +69,7 @@ export class SchemaFactoryAlpha< true, options?.allowUnknownOptionalFields ?? defaultSchemaFactoryObjectOptions.allowUnknownOptionalFields, + options?.metadata, ); } diff --git a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts index 208a01e5503c..ab17f92cdfb7 100644 --- a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts @@ -8,6 +8,7 @@ import { getJsonSchema, NodeKind, SchemaFactory, + SchemaFactoryAlpha, type JsonTreeSchema, } from "../../../simple-tree/index.js"; @@ -230,7 +231,7 @@ describe("getJsonSchema", () => { }); it("Object schema", () => { - const schemaFactory = new SchemaFactory("test"); + const schemaFactory = new SchemaFactoryAlpha("test"); const Schema = schemaFactory.object( "object", { diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index d00ba7025f4b..37ba6d792346 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -15,6 +15,7 @@ import { import { TreeStatus } from "../../../feature-libraries/index.js"; import { + SchemaFactoryAlpha, treeNodeApi as Tree, TreeViewConfiguration, type TreeArrayNode, @@ -364,7 +365,7 @@ describe("schemaFactory", () => { }); it("Node schema metadata", () => { - const factory = new SchemaFactory(""); + const factory = new SchemaFactoryAlpha(""); const fooMetadata = { description: "An object called Foo", diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts index 27d01417ce5e..336b3c8a9182 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts @@ -22,6 +22,7 @@ import { type FlexListToUnion, type ApplyKindInput, type NodeBuilderData, + SchemaFactoryAlpha, } from "../../../simple-tree/index.js"; import type { ValidateRecursiveSchema, @@ -458,7 +459,7 @@ describe("SchemaFactory Recursive methods", () => { }); it("Node schema metadata", () => { - const factory = new SchemaFactory(""); + const factory = new SchemaFactoryAlpha(""); class Foo extends factory.objectRecursive( "Foo", diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index d76eae4192b3..8bdd0e6afb2b 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -991,8 +991,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index b57e1261f386..a75d73443328 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -749,8 +749,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index 687b0f61c6c2..a88befaddbfd 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -1047,8 +1047,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index b655cbdddf1c..fc4a3ce17336 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -780,8 +780,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index 6598b030c82f..3d4bd6aa695a 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -744,8 +744,8 @@ export class SchemaFactory; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; - object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; - objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; + object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; + objectRecursive>>(name: Name, t: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T>; optional(t: T, props?: Omit, "defaultProvider">): FieldSchema; optionalRecursive>(t: T, props?: Omit): FieldSchemaUnsafe; required(t: T, props?: Omit, "defaultProvider">): FieldSchema; From aab58a7c40f9e59db8c153bb09d79952c5454bf3 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:57:29 +0000 Subject: [PATCH 49/55] refactor: Move remaining method updates down to subclass --- .../dds/tree/api-report/tree.alpha.api.md | 25 ++- packages/dds/tree/api-report/tree.beta.api.md | 12 +- .../tree/api-report/tree.legacy.alpha.api.md | 12 +- .../tree/api-report/tree.legacy.public.api.md | 12 +- .../dds/tree/api-report/tree.public.api.md | 12 +- .../tree/src/simple-tree/api/schemaFactory.ts | 110 ++++--------- .../src/simple-tree/api/schemaFactoryAlpha.ts | 146 +++++++++++++++++- .../simple-tree/api/getJsonSchema.spec.ts | 8 +- .../simple-tree/api/schemaFactory.spec.ts | 8 +- .../api/schemaFactoryRecursive.spec.ts | 4 +- .../api-report/fluid-framework.alpha.api.md | 25 ++- .../api-report/fluid-framework.beta.api.md | 12 +- .../fluid-framework.legacy.alpha.api.md | 12 +- .../fluid-framework.legacy.public.api.md | 12 +- .../api-report/fluid-framework.public.api.md | 12 +- 15 files changed, 269 insertions(+), 153 deletions(-) diff --git a/packages/dds/tree/api-report/tree.alpha.api.md b/packages/dds/tree/api-report/tree.alpha.api.md index c645d90e731a..1fa7b3f0b692 100644 --- a/packages/dds/tree/api-report/tree.alpha.api.md +++ b/packages/dds/tree/api-report/tree.alpha.api.md @@ -610,23 +610,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; @@ -641,6 +641,19 @@ export class SchemaFactory extends SchemaFactory { + arrayAlpha(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + [Symbol.iterator](): Iterator>; + }, false, T, undefined, TCustomMetadata>; + mapAlpha(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + [Symbol.iterator](): Iterator<[ + string, + InsertableTreeNodeFromImplicitAllowedTypesUnsafe + ]>; + } | { + readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; + }, false, T, undefined, TCustomMetadata>; object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: SchemaFactoryObjectOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: SchemaFactoryObjectOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; } diff --git a/packages/dds/tree/api-report/tree.beta.api.md b/packages/dds/tree/api-report/tree.beta.api.md index 7323447b2787..4f1655de0a8e 100644 --- a/packages/dds/tree/api-report/tree.beta.api.md +++ b/packages/dds/tree/api-report/tree.beta.api.md @@ -371,23 +371,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; diff --git a/packages/dds/tree/api-report/tree.legacy.alpha.api.md b/packages/dds/tree/api-report/tree.legacy.alpha.api.md index 2c46bfd3e5ee..1ee33886234f 100644 --- a/packages/dds/tree/api-report/tree.legacy.alpha.api.md +++ b/packages/dds/tree/api-report/tree.legacy.alpha.api.md @@ -366,23 +366,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; diff --git a/packages/dds/tree/api-report/tree.legacy.public.api.md b/packages/dds/tree/api-report/tree.legacy.public.api.md index a8401d0a5eb9..8caed641af7f 100644 --- a/packages/dds/tree/api-report/tree.legacy.public.api.md +++ b/packages/dds/tree/api-report/tree.legacy.public.api.md @@ -366,23 +366,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; diff --git a/packages/dds/tree/api-report/tree.public.api.md b/packages/dds/tree/api-report/tree.public.api.md index a8401d0a5eb9..8caed641af7f 100644 --- a/packages/dds/tree/api-report/tree.public.api.md +++ b/packages/dds/tree/api-report/tree.public.api.md @@ -366,23 +366,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 947e6a6d3ebc..9a34acb80d69 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -40,7 +40,6 @@ import { createFieldSchema, type DefaultProvider, getDefaultProvider, - type NodeSchemaMetadata, type NodeSchemaOptions, } from "../schemaTypes.js"; import { inPrototypeChain } from "../core/index.js"; @@ -155,10 +154,11 @@ export interface SchemaFactoryObjectOptions allowUnknownOptionalFields?: boolean; } -export const defaultSchemaFactoryObjectOptions = { +export const defaultSchemaFactoryObjectOptions: Required< + Omit +> = { allowUnknownOptionalFields: false, - metadata: undefined, -} satisfies SchemaFactoryObjectOptions; +}; /** * The name of a schema produced by {@link SchemaFactory}, including its optional scope prefix. @@ -401,7 +401,6 @@ export class SchemaFactory< fields, true, defaultSchemaFactoryObjectOptions.allowUnknownOptionalFields, - defaultSchemaFactoryObjectOptions.metadata, ); } @@ -450,14 +449,9 @@ export class SchemaFactory< * class NamedMap extends factory.map("name", factory.number) {} * ``` */ - public map< - Name extends TName, - const T extends ImplicitAllowedTypes, - const TCustomMetadata = unknown, - >( + public map( name: Name, allowedTypes: T, - options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Map, @@ -465,8 +459,7 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined, - TCustomMetadata + undefined >; /** @@ -477,10 +470,9 @@ export class SchemaFactory< * This seems like a TypeScript bug getting variance backwards for overload return types since it's erroring when the relation between the overload * and the implementation is type safe, and forcing an unsafe typing instead. */ - public map( + public map( nameOrAllowedTypes: TName | ((T & TreeNodeSchema) | readonly TreeNodeSchema[]), allowedTypes?: T, - options?: NodeSchemaOptions, ): TreeNodeSchema, MapNodeInsertableData, true, T> { if (allowedTypes === undefined) { const types = nameOrAllowedTypes as (T & TreeNodeSchema) | readonly TreeNodeSchema[]; @@ -494,7 +486,6 @@ export class SchemaFactory< nameOrAllowedTypes as T, false, true, - options?.metadata, ) as TreeNodeSchema, ) as TreeNodeSchemaBoth< string, @@ -503,8 +494,7 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined, - TCustomMetadata + undefined >; } // To actually have type safety, assign to the type this method should return before implicitly upcasting when returning. @@ -515,15 +505,8 @@ export class SchemaFactory< MapNodeInsertableData, true, T, - undefined, - TCustomMetadata - > = this.namedMap( - nameOrAllowedTypes as TName, - allowedTypes, - true, - true, - options?.metadata, - ); + undefined + > = this.namedMap(nameOrAllowedTypes as TName, allowedTypes, true, true); return out; } @@ -536,13 +519,11 @@ export class SchemaFactory< Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, - TCustomMetadata = unknown, >( name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable, - metadata: NodeSchemaMetadata | undefined, ): TreeNodeSchemaBoth< ScopedSchemaName, NodeKind.Map, @@ -550,8 +531,7 @@ export class SchemaFactory< MapNodeInsertableData, ImplicitlyConstructable, T, - undefined, - TCustomMetadata + undefined > { return mapSchema( this.scoped(name), @@ -559,7 +539,7 @@ export class SchemaFactory< implicitlyConstructable, // The current policy is customizable nodes don't get fake prototypes. !customizable, - metadata, + undefined, ); } @@ -612,6 +592,7 @@ export class SchemaFactory< * Define (and add to this library) a {@link TreeNodeSchemaClass} for a {@link (TreeArrayNode:interface)}. * * @param name - Unique identifier for this schema within this factory's scope. + * @param allowedTypes - The types of nodes that may appear as values in the map. * * @example * ```typescript @@ -620,14 +601,9 @@ export class SchemaFactory< * * {@label NAMED} */ - public array< - const Name extends TName, - const T extends ImplicitAllowedTypes, - const TCustomMetadata = unknown, - >( + public array( name: Name, allowedTypes: T, - options?: NodeSchemaOptions, ): TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Array, @@ -635,8 +611,7 @@ export class SchemaFactory< Iterable>, true, T, - undefined, - TCustomMetadata + undefined >; /** @@ -645,24 +620,22 @@ export class SchemaFactory< * @privateRemarks * This should return TreeNodeSchemaBoth: see note on "map" implementation for details. */ - public array( + public array( nameOrAllowedTypes: TName | ((T & TreeNodeSchema) | readonly TreeNodeSchema[]), allowedTypes?: T, - options?: NodeSchemaOptions, ): TreeNodeSchema< ScopedSchemaName, NodeKind.Array, TreeArrayNode, Iterable>, true, - T, - TCustomMetadata + T > { if (allowedTypes === undefined) { const types = nameOrAllowedTypes as (T & TreeNodeSchema) | readonly TreeNodeSchema[]; const fullName = structuralName("Array", types); return getOrCreate(this.structuralTypes, fullName, () => - this.namedArray(fullName, nameOrAllowedTypes as T, false, true, options?.metadata), + this.namedArray(fullName, nameOrAllowedTypes as T, false, true), ) as TreeNodeSchemaClass< ScopedSchemaName, NodeKind.Array, @@ -670,8 +643,7 @@ export class SchemaFactory< Iterable>, true, T, - undefined, - TCustomMetadata + undefined >; } const out: TreeNodeSchemaBoth< @@ -681,15 +653,8 @@ export class SchemaFactory< Iterable>, true, T, - undefined, - TCustomMetadata - > = this.namedArray( - nameOrAllowedTypes as TName, - allowedTypes, - true, - true, - options?.metadata, - ); + undefined + > = this.namedArray(nameOrAllowedTypes as TName, allowedTypes, true, true); return out; } @@ -706,13 +671,11 @@ export class SchemaFactory< Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean, - const TCustomMetadata = unknown, >( name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable, - metadata: NodeSchemaMetadata | undefined, ): TreeNodeSchemaBoth< ScopedSchemaName, NodeKind.Array, @@ -720,16 +683,9 @@ export class SchemaFactory< Iterable>, ImplicitlyConstructable, T, - undefined, - TCustomMetadata + undefined > { - return arraySchema( - this.scoped(name), - allowedTypes, - implicitlyConstructable, - customizable, - metadata, - ); + return arraySchema(this.scoped(name), allowedTypes, implicitlyConstructable, customizable); } /** @@ -883,14 +839,12 @@ export class SchemaFactory< public arrayRecursive< const Name extends TName, const T extends Unenforced, - const TCustomMetadata = unknown, - >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { + >(name: Name, allowedTypes: T) { const RecursiveArray = this.namedArray( name, allowedTypes as T & ImplicitAllowedTypes, true, false, - options?.metadata, ); return RecursiveArray as TreeNodeSchemaClass< @@ -913,8 +867,7 @@ export class SchemaFactory< }, false, T, - undefined, - TCustomMetadata + undefined >; } @@ -926,11 +879,10 @@ export class SchemaFactory< * See {@link ValidateRecursiveSchema} for additional information about using recursive schema. */ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - public mapRecursive< - Name extends TName, - const T extends Unenforced, - const TCustomMetadata = unknown, - >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { + public mapRecursive>( + name: Name, + allowedTypes: T, + ) { const MapSchema = this.namedMap( name, allowedTypes as T & ImplicitAllowedTypes, @@ -938,7 +890,6 @@ export class SchemaFactory< // Setting this (implicitlyConstructable) to true seems to work ok currently, but not for other node kinds. // Supporting this could be fragile and might break other future changes, so it's being kept as false for now. false, - options?.metadata, ); return MapSchema as TreeNodeSchemaClass< @@ -970,8 +921,7 @@ export class SchemaFactory< }, false, T, - undefined, - TCustomMetadata + undefined >; } } diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts b/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts index 071f04108e2c..0cd6f2f4dffb 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts @@ -14,11 +14,23 @@ import { SchemaFactory, type SchemaFactoryObjectOptions, } from "./schemaFactory.js"; -import type { ImplicitFieldSchema } from "../schemaTypes.js"; +import type { + ImplicitAllowedTypes, + ImplicitFieldSchema, + InsertableTreeNodeFromImplicitAllowedTypes, + NodeSchemaOptions, +} from "../schemaTypes.js"; import { type TreeObjectNode, objectSchema } from "../objectNode.js"; import type { RestrictiveStringRecord } from "../../util/index.js"; -import type { NodeKind, TreeNodeSchemaClass } from "../core/index.js"; -import type { Unenforced } from "./typesUnsafe.js"; +import type { NodeKind, TreeNodeSchemaClass, WithType } from "../core/index.js"; +import type { + InsertableTreeNodeFromImplicitAllowedTypesUnsafe, + TreeArrayNodeUnsafe, + TreeMapNodeUnsafe, + Unenforced, +} from "./typesUnsafe.js"; +import { mapSchema, type MapNodeInsertableData, type TreeMapNode } from "../mapNode.js"; +import { arraySchema, type TreeArrayNode } from "../arrayNode.js"; /** * {@link SchemaFactory} with additional alpha APIs. @@ -44,6 +56,7 @@ export class SchemaFactoryAlpha< * * @param name - Unique identifier for this schema within this factory's scope. * @param fields - Schema for fields of the object node's schema. Defines what children can be placed under each key. + * @param options - Additional options for the schema. */ public override object< const Name extends TName, @@ -110,4 +123,131 @@ export class SchemaFactoryAlpha< TCustomMetadata >; } + + /** + * Define a {@link TreeNodeSchema} for a {@link TreeMapNode}. + * + * @param name - Unique identifier for this schema within this factory's scope. + * @param allowedTypes - The types of nodes that may appear as values in the map. + * @param options - Additional options for the schema. + * + * @example + * ```typescript + * class NamedMap extends factory.map("name", factory.number, { + * metadata: { description: "A map of numbers" } + * }) {} + * ``` + */ + public mapAlpha< + Name extends TName, + const T extends ImplicitAllowedTypes, + const TCustomMetadata = unknown, + >( + name: Name, + allowedTypes: T, + options?: NodeSchemaOptions, + ): TreeNodeSchemaClass< + ScopedSchemaName, + NodeKind.Map, + TreeMapNode & WithType, NodeKind.Map>, + MapNodeInsertableData, + true, + T, + undefined, + TCustomMetadata + > { + return mapSchema(this.scoped2(name), allowedTypes, true, true, options?.metadata); + } + + /** + * {@inheritDoc SchemaFactory.objectRecursive} + */ + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + public override mapRecursive< + Name extends TName, + const T extends Unenforced, + const TCustomMetadata = unknown, + >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { + return this.mapAlpha( + name, + allowedTypes as T & ImplicitAllowedTypes, + options, + ) as unknown as TreeNodeSchemaClass< + ScopedSchemaName, + NodeKind.Map, + TreeMapNodeUnsafe & WithType, NodeKind.Map>, + | { + [Symbol.iterator](): Iterator< + [string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe] + >; + } + | { + readonly [P in string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; + }, + false, + T, + undefined, + TCustomMetadata + >; + } + + /** + * Define (and add to this library) a {@link TreeNodeSchemaClass} for a {@link (TreeArrayNode:interface)}. + * + * @param name - Unique identifier for this schema within this factory's scope. + * @param allowedTypes - The types of nodes that may appear in the array. + * @param options - Additional options for the schema. + * + * @example + * ```typescript + * class NamedArray extends factory.array("name", factory.number) {} + * ``` + */ + public arrayAlpha< + const Name extends TName, + const T extends ImplicitAllowedTypes, + const TCustomMetadata = unknown, + >( + name: Name, + allowedTypes: T, + options?: NodeSchemaOptions, + ): TreeNodeSchemaClass< + ScopedSchemaName, + NodeKind.Array, + TreeArrayNode & WithType, NodeKind.Array>, + Iterable>, + true, + T, + undefined, + TCustomMetadata + > { + return arraySchema(this.scoped2(name), allowedTypes, true, true, options?.metadata); + } + + /** + * {@inheritDoc SchemaFactory.objectRecursive} + */ + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + public override arrayRecursive< + const Name extends TName, + const T extends Unenforced, + const TCustomMetadata = unknown, + >(name: Name, allowedTypes: T, options?: NodeSchemaOptions) { + return this.arrayAlpha( + name, + allowedTypes as T & ImplicitAllowedTypes, + options, + ) as unknown as TreeNodeSchemaClass< + ScopedSchemaName, + NodeKind.Array, + TreeArrayNodeUnsafe & WithType, NodeKind.Array>, + { + [Symbol.iterator](): Iterator>; + }, + false, + T, + undefined, + TCustomMetadata + >; + } } diff --git a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts index ab17f92cdfb7..c4ee936581c4 100644 --- a/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/getJsonSchema.spec.ts @@ -126,8 +126,8 @@ describe("getJsonSchema", () => { }); it("Array schema", () => { - const schemaFactory = new SchemaFactory("test"); - const Schema = schemaFactory.array("array", schemaFactory.string, { + const schemaFactory = new SchemaFactoryAlpha("test"); + const Schema = schemaFactory.arrayAlpha("array", schemaFactory.string, { metadata: { description: "An array of strings", }, @@ -169,8 +169,8 @@ describe("getJsonSchema", () => { }); it("Map schema", () => { - const schemaFactory = new SchemaFactory("test"); - const Schema = schemaFactory.map("map", schemaFactory.string, { + const schemaFactory = new SchemaFactoryAlpha("test"); + const Schema = schemaFactory.mapAlpha("map", schemaFactory.string, { metadata: { description: "A map containing strings", }, diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts index 37ba6d792346..121a0dc50291 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactory.spec.ts @@ -569,7 +569,7 @@ describe("schemaFactory", () => { }); it("Node schema metadata", () => { - const factory = new SchemaFactory(""); + const factory = new SchemaFactoryAlpha(""); const fooMetadata = { description: "An array of numbers", @@ -578,7 +578,7 @@ describe("schemaFactory", () => { }, }; - class Foo extends factory.array("Foo", factory.number, { metadata: fooMetadata }) {} + class Foo extends factory.arrayAlpha("Foo", factory.number, { metadata: fooMetadata }) {} assert.deepEqual(Foo.metadata, fooMetadata); @@ -644,7 +644,7 @@ describe("schemaFactory", () => { }); it("Node schema metadata", () => { - const factory = new SchemaFactory(""); + const factory = new SchemaFactoryAlpha(""); const fooMetadata = { description: "A map of numbers", @@ -653,7 +653,7 @@ describe("schemaFactory", () => { }, }; - class Foo extends factory.map("Foo", factory.number, { metadata: fooMetadata }) {} + class Foo extends factory.mapAlpha("Foo", factory.number, { metadata: fooMetadata }) {} assert.deepEqual(Foo.metadata, fooMetadata); diff --git a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts index 336b3c8a9182..c960e1ac3e2f 100644 --- a/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts +++ b/packages/dds/tree/src/test/simple-tree/api/schemaFactoryRecursive.spec.ts @@ -614,7 +614,7 @@ describe("SchemaFactory Recursive methods", () => { }); it("Node schema metadata", () => { - const factory = new SchemaFactory(""); + const factory = new SchemaFactoryAlpha(""); class Foo extends factory.objectRecursive("Foo", { fooList: sf.arrayRecursive("FooList", [() => Foo]), @@ -680,7 +680,7 @@ describe("SchemaFactory Recursive methods", () => { }); it("Node schema metadata", () => { - const factory = new SchemaFactory(""); + const factory = new SchemaFactoryAlpha(""); class Foo extends factory.objectRecursive("Foo", { fooList: sf.arrayRecursive("FooList", [() => Foo]), diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md index 8bdd0e6afb2b..60ecee6b695d 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md @@ -972,23 +972,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; @@ -1003,6 +1003,19 @@ export class SchemaFactory extends SchemaFactory { + arrayAlpha(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; + arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + [Symbol.iterator](): Iterator>; + }, false, T, undefined, TCustomMetadata>; + mapAlpha(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; + mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + [Symbol.iterator](): Iterator<[ + string, + InsertableTreeNodeFromImplicitAllowedTypesUnsafe + ]>; + } | { + readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; + }, false, T, undefined, TCustomMetadata>; object, const TCustomMetadata = unknown>(name: Name, fields: T, options?: SchemaFactoryObjectOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T, never, TCustomMetadata>; objectRecursive>, const TCustomMetadata = unknown>(name: Name, t: T, options?: SchemaFactoryObjectOptions): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNodeUnsafe>, object & InsertableObjectFromSchemaRecordUnsafe, false, T, never, TCustomMetadata>; } diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md index a75d73443328..60462048e315 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.beta.api.md @@ -730,23 +730,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md index a88befaddbfd..6f4225b3418a 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.alpha.api.md @@ -1028,23 +1028,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md index fc4a3ce17336..e4cc49c1ca71 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.legacy.public.api.md @@ -761,23 +761,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; diff --git a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md index 3d4bd6aa695a..26762b5d926d 100644 --- a/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md +++ b/packages/framework/fluid-framework/api-report/fluid-framework.public.api.md @@ -725,23 +725,23 @@ export class SchemaFactory(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Array, TreeArrayNode & WithType`>, NodeKind.Array>, Iterable>, true, T, undefined>; - array(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined, TCustomMetadata>; - arrayRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { + array(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNode & WithType, NodeKind.Array>, Iterable>, true, T, undefined>; + arrayRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Array, TreeArrayNodeUnsafe & WithType, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator>; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>; readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, IFluidHandle, IFluidHandle, true, unknown, never, unknown>; get identifier(): FieldSchema; map(allowedTypes: T): TreeNodeSchemaNonClass`>, NodeKind.Map, TreeMapNode & WithType`>, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; - map(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined, TCustomMetadata>; - mapRecursive, const TCustomMetadata = unknown>(name: Name, allowedTypes: T, options?: NodeSchemaOptions): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { + map(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNode & WithType, NodeKind.Map>, MapNodeInsertableData, true, T, undefined>; + mapRecursive>(name: Name, allowedTypes: T): TreeNodeSchemaClass, NodeKind.Map, TreeMapNodeUnsafe & WithType, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe; - }, false, T, undefined, TCustomMetadata>; + }, false, T, undefined>; readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>; readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>; object>(name: Name, fields: T): TreeNodeSchemaClass, NodeKind.Object, TreeObjectNode>, object & InsertableObjectFromSchemaRecord, true, T>; From 93d0ab2f977f1071307b97e5700b5c77cb08f745 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:00:45 +0000 Subject: [PATCH 50/55] docs: Param comments --- packages/dds/tree/src/simple-tree/api/schemaFactory.ts | 7 ++++++- .../dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts index 9a34acb80d69..af9d390a4a3a 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactory.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactory.ts @@ -407,6 +407,8 @@ export class SchemaFactory< /** * Define a structurally typed {@link TreeNodeSchema} for a {@link TreeMapNode}. * + * @param allowedTypes - The types that may appear as values in the map. + * * @remarks * The unique identifier for this Map is defined as a function of the provided types. * It is still scoped to this SchemaBuilder, but multiple calls with the same arguments will return the same schema object, providing somewhat structural typing. @@ -443,6 +445,7 @@ export class SchemaFactory< * Define a {@link TreeNodeSchema} for a {@link TreeMapNode}. * * @param name - Unique identifier for this schema within this factory's scope. + * @param allowedTypes - The types that may appear as values in the map. * * @example * ```typescript @@ -546,6 +549,8 @@ export class SchemaFactory< /** * Define a structurally typed {@link TreeNodeSchema} for a {@link (TreeArrayNode:interface)}. * + * @param allowedTypes - The types that may appear in the array. + * * @remarks * The identifier for this Array is defined as a function of the provided types. * It is still scoped to this SchemaFactory, but multiple calls with the same arguments will return the same schema object, providing somewhat structural typing. @@ -592,7 +597,7 @@ export class SchemaFactory< * Define (and add to this library) a {@link TreeNodeSchemaClass} for a {@link (TreeArrayNode:interface)}. * * @param name - Unique identifier for this schema within this factory's scope. - * @param allowedTypes - The types of nodes that may appear as values in the map. + * @param allowedTypes - The types that may appear in the array. * * @example * ```typescript diff --git a/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts b/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts index 0cd6f2f4dffb..0693e53b8e02 100644 --- a/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts +++ b/packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts @@ -128,7 +128,7 @@ export class SchemaFactoryAlpha< * Define a {@link TreeNodeSchema} for a {@link TreeMapNode}. * * @param name - Unique identifier for this schema within this factory's scope. - * @param allowedTypes - The types of nodes that may appear as values in the map. + * @param allowedTypes - The types that may appear as values in the map. * @param options - Additional options for the schema. * * @example @@ -195,7 +195,7 @@ export class SchemaFactoryAlpha< * Define (and add to this library) a {@link TreeNodeSchemaClass} for a {@link (TreeArrayNode:interface)}. * * @param name - Unique identifier for this schema within this factory's scope. - * @param allowedTypes - The types of nodes that may appear in the array. + * @param allowedTypes - The types that may appear in the array. * @param options - Additional options for the schema. * * @example From 704277e8d252140df213018e50a12e155a12721c Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:12:50 +0000 Subject: [PATCH 51/55] feat(ai-collab example) Leverage new alpha methods --- .../src/types/sharedTreeAppSchema.ts | 170 ++++++++++-------- 1 file changed, 95 insertions(+), 75 deletions(-) diff --git a/examples/apps/ai-collab/src/types/sharedTreeAppSchema.ts b/examples/apps/ai-collab/src/types/sharedTreeAppSchema.ts index e9ab918e99f3..2959d66f3a96 100644 --- a/examples/apps/ai-collab/src/types/sharedTreeAppSchema.ts +++ b/examples/apps/ai-collab/src/types/sharedTreeAppSchema.ts @@ -3,99 +3,119 @@ * Licensed under the MIT License. */ -import { - SchemaFactory, - Tree, - TreeViewConfiguration, - type TreeNode, -} from "@fluidframework/tree"; +import { Tree, TreeViewConfiguration, type TreeNode } from "@fluidframework/tree"; +import { SchemaFactoryAlpha } from "@fluidframework/tree/alpha"; import { SharedTree } from "fluid-framework"; // The string passed to the SchemaFactory should be unique -const sf = new SchemaFactory("ai-collab-sample-application"); +const sf = new SchemaFactoryAlpha("ai-collab-sample-application"); // NOTE that there is currently a bug with the ai-collab library that requires us to rearrange the keys of each type to not have the same first key. -export class SharedTreeTask extends sf.object("Task", { - title: sf.required(sf.string, { +export class SharedTreeTask extends sf.object( + "Task", + { + title: sf.required(sf.string, { + metadata: { + description: `The title of the task.`, + }, + }), + id: sf.identifier, + description: sf.required(sf.string, { + metadata: { + description: `The description of the task.`, + }, + }), + priority: sf.required(sf.string, { + metadata: { + description: `The priority of the task which can ONLY be one of three levels: "Low", "Medium", "High" (case-sensitive).`, + }, + }), + complexity: sf.required(sf.number, { + metadata: { + description: `The complexity of the task as a fibonacci number.`, + }, + }), + status: sf.required(sf.string, { + metadata: { + description: `The status of the task which can ONLY be one of the following values: "To Do", "In Progress", "Done" (case-sensitive).`, + }, + }), + assignee: sf.required(sf.string, { + metadata: { + description: `The name of the tasks assignee e.g. "Bob" or "Alice".`, + }, + }), + }, + { metadata: { - description: `The title of the task.`, + description: `A task that can be assigned to an engineer.`, }, - }), - id: sf.identifier, - description: sf.required(sf.string, { - metadata: { - description: `The description of the task.`, - }, - }), - priority: sf.required(sf.string, { - metadata: { - description: `The priority of the task which can ONLY be one of three levels: "Low", "Medium", "High" (case-sensitive).`, - }, - }), - complexity: sf.required(sf.number, { - metadata: { - description: `The complexity of the task as a fibonacci number.`, - }, - }), - status: sf.required(sf.string, { - metadata: { - description: `The status of the task which can ONLY be one of the following values: "To Do", "In Progress", "Done" (case-sensitive).`, - }, - }), - assignee: sf.required(sf.string, { - metadata: { - description: `The name of the tasks assignee e.g. "Bob" or "Alice".`, - }, - }), -}) {} + }, +) {} export class SharedTreeTaskList extends sf.array("TaskList", SharedTreeTask) {} -export class SharedTreeEngineer extends sf.object("Engineer", { - name: sf.required(sf.string, { - metadata: { - description: `The name of an engineer whom can be assigned to a task.`, - }, - }), - id: sf.identifier, - skills: sf.required(sf.string, { - metadata: { - description: `A description of the engineers skills which influence what types of tasks they should be assigned to.`, - }, - }), - maxCapacity: sf.required(sf.number, { +export class SharedTreeEngineer extends sf.object( + "Engineer", + { + name: sf.required(sf.string, { + metadata: { + description: `The name of the engineer.`, + }, + }), + id: sf.identifier, + skills: sf.required(sf.string, { + metadata: { + description: `A description of the engineer's skills, which influence what types of tasks they should be assigned to.`, + }, + }), + maxCapacity: sf.required(sf.number, { + metadata: { + description: `The maximum capacity of tasks this engineer can handle, measured in task complexity points.`, + }, + }), + }, + { metadata: { - description: `The maximum capacity of tasks this engineer can handle measured in in task complexity points.`, + description: `An engineer to whom tasks may be assigned.`, }, - }), -}) {} + }, +) {} export class SharedTreeEngineerList extends sf.array("EngineerList", SharedTreeEngineer) {} -export class SharedTreeTaskGroup extends sf.object("TaskGroup", { - description: sf.required(sf.string, { - metadata: { - description: `The description of the task group, which is a collection of tasks and engineers that can be assigned to said tasks.`, - }, - }), - id: sf.identifier, - title: sf.required(sf.string, { +export class SharedTreeTaskGroup extends sf.object( + "TaskGroup", + { + description: sf.required(sf.string, { + metadata: { + description: `The description of the task group.`, + }, + }), + id: sf.identifier, + title: sf.required(sf.string, { + metadata: { + description: `The title of the task group.`, + }, + }), + tasks: sf.required(SharedTreeTaskList, { + metadata: { + description: `The lists of tasks within this task group.`, + }, + }), + engineers: sf.required(SharedTreeEngineerList, { + metadata: { + description: `The lists of engineers within this task group to whom tasks may be assigned.`, + }, + }), + }, + { metadata: { - description: `The title of the task group.`, + description: "A collection of tasks and engineers to whom tasks may be assigned.", }, - }), - tasks: sf.required(SharedTreeTaskList, { - metadata: { - description: `The lists of tasks within this task group.`, - }, - }), - engineers: sf.required(SharedTreeEngineerList, { - metadata: { - description: `The lists of engineers within this task group which can be assigned to tasks.`, - }, - }), -}) {} + }, +) {} export class SharedTreeTaskGroupList extends sf.array("TaskGroupList", SharedTreeTaskGroup) {} From 15c9a7b112c37bc937c170b36d1900d9aecc1eca Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:05:55 -0800 Subject: [PATCH 52/55] docs: Consistent wording --- .../dds/tree/src/simple-tree/api/viewSchemaToSimpleSchema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dds/tree/src/simple-tree/api/viewSchemaToSimpleSchema.ts b/packages/dds/tree/src/simple-tree/api/viewSchemaToSimpleSchema.ts index 0d7b9405259e..6d4542deef28 100644 --- a/packages/dds/tree/src/simple-tree/api/viewSchemaToSimpleSchema.ts +++ b/packages/dds/tree/src/simple-tree/api/viewSchemaToSimpleSchema.ts @@ -41,7 +41,7 @@ export function toSimpleTreeSchema(schema: ImplicitFieldSchema): SimpleTreeSchem definitions, }; - // Include the "metadata" property only if it's present on the input. + // Only include "metadata" property if it is present in the input. if (normalizedSchema.metadata !== undefined) { output.metadata = normalizedSchema.metadata; } From 4c8d0c39e830b419949d03b6d82a2f8c1696e33f Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:48:37 +0000 Subject: [PATCH 53/55] docs: Update changeset --- .changeset/grey-triangles-shout.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index 419386235234..f62979fb953c 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -7,13 +7,13 @@ section: tree Metadata can be associated with Node Schema -Users of TreeView can now specify metadata when creating Node Schema. +Users of TreeView can now specify metadata when creating Node Schema, via `SchemaFactoryAlpha`. This metadata may include system-understood properties like `description`. Example: ```typescript - +const schemaFactory = new SchemaFactoryAlpha(...); class Point extends schemaFactory.object("Point", { x: schemaFactory.required(schemaFactory.number), y: schemaFactory.required(schemaFactory.number), @@ -48,6 +48,7 @@ interface AppMetadata { searchIgnore?: boolean; } +const schemaFactory = new SchemaFactoryAlpha(...); class Point extends schemaFactory.object("Point", { x: schemaFactory.required(schemaFactory.number), y: schemaFactory.required(schemaFactory.number), From 2c2b63559b611ed0777d37953712aecfe9ec1854 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Sat, 21 Dec 2024 00:57:43 +0000 Subject: [PATCH 54/55] revert: Unwanted change --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b40e1694e0d1..29ef09ef141d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -62,7 +62,7 @@ "unacked", "unaugmented", "undoprovider", - "unsequenced" + "unsequenced", ], // Enable biome as default formatter, and disable rules that disagree with it From 8e77bb8328ccba42b532d0143e0c291b30241046 Mon Sep 17 00:00:00 2001 From: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com> Date: Sat, 21 Dec 2024 01:01:06 +0000 Subject: [PATCH 55/55] docs: Update changeset --- .changeset/grey-triangles-shout.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.changeset/grey-triangles-shout.md b/.changeset/grey-triangles-shout.md index f62979fb953c..1e4c66331aa6 100644 --- a/.changeset/grey-triangles-shout.md +++ b/.changeset/grey-triangles-shout.md @@ -32,6 +32,12 @@ In the case of the `description` property, it is mapped directly to the `descrip Custom, user-defined properties can also be specified. These properties will not be used by the system by default, but can be used to associate common application-specific properties with Node Schema. +#### `SchemaFactoryAlpha` Updates + +- `object` and `objectRecursive`, `arrayRecursive`, and `mapRecursive` now support `metadata` in their `options` parameter. +- (new) `arrayAlpha` - Variant of `array` that accepts an options parameter which supports `metadata` +- (new) `mapAlpha` - Variant of `map` that accepts an options parameter which supports `metadata` + #### Example An application is implementing search functionality.