tree: Make SchematizingSimpleTreeView implement TreeViewAlpha (#22953)

## Description

Make SchematizingSimpleTreeView implement TreeViewAlpha, and add some
helper types.
This commit is contained in:
Craig Macomber (Microsoft) 2024-10-31 16:22:21 -07:00 коммит произвёл GitHub
Родитель 62ae4c541b
Коммит 512e53f04e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
13 изменённых файлов: 130 добавлений и 47 удалений

Просмотреть файл

@ -152,7 +152,7 @@ export enum ForestType {
export function getBranch(tree: ITree): TreeBranch;
// @alpha
export function getBranch<T extends ImplicitFieldSchema>(view: TreeView<T>): TreeBranch;
export function getBranch<T extends ImplicitFieldSchema | UnsafeUnknownSchema>(view: TreeViewAlpha<T>): TreeBranch;
// @alpha
export function getJsonSchema(schema: ImplicitFieldSchema): JsonTreeSchema;
@ -447,6 +447,9 @@ export type Off = () => void;
// @alpha
export type PopUnion<Union, AsOverloadedFunction = UnionToIntersection<Union extends unknown ? (f: Union) => void : never>> = AsOverloadedFunction extends (a: infer First) => void ? First : never;
// @alpha
export type ReadableField<TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> = TSchema extends ImplicitFieldSchema ? TreeFieldFromImplicitField<TSchema> : TreeLeafValue | TreeNode;
// @public @sealed
export interface ReadonlyArrayNode<out T = TreeNode | TreeLeafValue> extends ReadonlyArray<T>, Awaited<TreeNode & WithType<string, NodeKind.Array>> {
}
@ -467,6 +470,11 @@ interface ReadonlyMapInlined<K, T extends Unenforced<ImplicitAllowedTypes>> {
values(): IterableIterator<TreeNodeFromImplicitAllowedTypesUnsafe<T>>;
}
// @alpha
export type ReadSchema<TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> = [
TSchema
] extends [ImplicitFieldSchema] ? TSchema : ImplicitFieldSchema;
// @public @deprecated
export type RestrictiveReadonlyRecord<K extends symbol | string, T> = {
readonly [P in symbol | string]: P extends K ? T : never;
@ -793,11 +801,11 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
}
// @alpha
export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> extends Omit<TreeView<TSchema extends ImplicitFieldSchema ? TSchema : ImplicitFieldSchema>, "root" | "initialize"> {
export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> extends Omit<TreeView<ReadSchema<TSchema>>, "root" | "initialize"> {
// (undocumented)
initialize(content: InsertableField<TSchema>): void;
// (undocumented)
get root(): TSchema extends ImplicitFieldSchema ? TreeFieldFromImplicitField<TSchema> : TreeLeafValue | TreeNode;
get root(): ReadableField<TSchema>;
set root(newRoot: InsertableField<TSchema>);
}

Просмотреть файл

@ -133,6 +133,8 @@ export {
type InsertableContent,
type FactoryContent,
type FactoryContentObject,
type ReadableField,
type ReadSchema,
// test recursive schema for checking that d.ts files handles schema correctly
test_RecursiveObject,
test_RecursiveObject_base,

Просмотреть файл

@ -29,8 +29,6 @@ import {
type FieldSchema,
type ImplicitFieldSchema,
type SchemaCompatibilityStatus,
type InsertableTreeFieldFromImplicitField,
type TreeFieldFromImplicitField,
type TreeView,
type TreeViewEvents,
getTreeNodeForField,
@ -43,6 +41,11 @@ import {
prepareContentForHydration,
comparePersistedSchemaInternal,
toStoredSchema,
type TreeViewAlpha,
type InsertableField,
type ReadableField,
type ReadSchema,
type UnsafeUnknownSchema,
} from "../simple-tree/index.js";
import { Breakable, breakingClass, disposeSymbol, type WithBreakable } from "../util/index.js";
@ -60,8 +63,9 @@ export const ViewSlot = anchorSlot<TreeView<ImplicitFieldSchema>>();
* Implementation of TreeView wrapping a FlexTreeView.
*/
@breakingClass
export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitFieldSchema>
implements TreeView<TRootSchema>, WithBreakable
export class SchematizingSimpleTreeView<
in out TRootSchema extends ImplicitFieldSchema | UnsafeUnknownSchema,
> implements TreeViewAlpha<TRootSchema>, WithBreakable
{
/**
* The view is set to undefined when this object is disposed or the view schema does not support viewing the document's stored schema.
@ -96,7 +100,7 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
public constructor(
public readonly checkout: TreeCheckout,
public readonly config: TreeViewConfiguration<TRootSchema>,
public readonly config: TreeViewConfiguration<ReadSchema<TRootSchema>>,
public readonly nodeKeyManager: NodeKeyManager,
public readonly breaker: Breakable = new Breakable("SchematizingSimpleTreeView"),
private readonly onDispose?: () => void,
@ -130,11 +134,11 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
);
}
public get schema(): TRootSchema {
public get schema(): ReadSchema<TRootSchema> {
return this.config.schema;
}
public initialize(content: InsertableTreeFieldFromImplicitField<TRootSchema>): void {
public initialize(content: InsertableField<TRootSchema>): void {
this.ensureUndisposed();
const compatibility = this.compatibility;
@ -340,7 +344,7 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
this.onDispose?.();
}
public get root(): TreeFieldFromImplicitField<TRootSchema> {
public get root(): ReadableField<TRootSchema> {
this.breaker.use();
if (!this.compatibility.canView) {
throw new UsageError(
@ -348,10 +352,10 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
);
}
const view = this.getView();
return getTreeNodeForField(view.flexTree) as TreeFieldFromImplicitField<TRootSchema>;
return getTreeNodeForField(view.flexTree) as ReadableField<TRootSchema>;
}
public set root(newRoot: InsertableTreeFieldFromImplicitField<TRootSchema>) {
public set root(newRoot: InsertableField<TRootSchema>) {
this.breaker.use();
if (!this.compatibility.canView) {
throw new UsageError(

Просмотреть файл

@ -53,8 +53,11 @@ import {
import type {
ITree,
ImplicitFieldSchema,
ReadSchema,
TreeView,
TreeViewAlpha,
TreeViewConfiguration,
UnsafeUnknownSchema,
} from "../simple-tree/index.js";
import { SchematizingSimpleTreeView } from "./schematizingTreeView.js";
@ -324,10 +327,21 @@ export class SharedTree
}
}
// For the new TreeViewAlpha API
public viewWith<TRoot extends ImplicitFieldSchema | UnsafeUnknownSchema>(
config: TreeViewConfiguration<ReadSchema<TRoot>>,
): SchematizingSimpleTreeView<TRoot> & TreeView<ReadSchema<TRoot>>;
// For the old TreeView API
public viewWith<TRoot extends ImplicitFieldSchema>(
config: TreeViewConfiguration<TRoot>,
): SchematizingSimpleTreeView<TRoot> {
return this.checkout.viewWith(config);
): SchematizingSimpleTreeView<TRoot> & TreeView<TRoot>;
public viewWith<TRoot extends ImplicitFieldSchema | UnsafeUnknownSchema>(
config: TreeViewConfiguration<ReadSchema<TRoot>>,
): SchematizingSimpleTreeView<TRoot> & TreeView<ReadSchema<TRoot>> {
return this.checkout.viewWith(config) as SchematizingSimpleTreeView<TRoot> &
TreeView<ReadSchema<TRoot>>;
}
protected override async loadCore(services: IChannelStorageService): Promise<void> {
@ -353,9 +367,11 @@ export function getBranch(tree: ITree): TreeBranch;
* but it (or something like it) is necessary in the meantime to prevent the alpha types from being exposed as public.
* @alpha
*/
export function getBranch<T extends ImplicitFieldSchema>(view: TreeView<T>): TreeBranch;
export function getBranch<T extends ImplicitFieldSchema>(
treeOrView: ITree | TreeView<T>,
export function getBranch<T extends ImplicitFieldSchema | UnsafeUnknownSchema>(
view: TreeViewAlpha<T>,
): TreeBranch;
export function getBranch<T extends ImplicitFieldSchema | UnsafeUnknownSchema>(
treeOrView: ITree | TreeViewAlpha<T>,
): TreeBranch {
assert(
treeOrView instanceof SharedTree || treeOrView instanceof SchematizingSimpleTreeView,

Просмотреть файл

@ -63,8 +63,10 @@ import type { ISharedTreeEditor, SharedTreeEditBuilder } from "./sharedTreeEditB
import type { IDisposable } from "@fluidframework/core-interfaces";
import type {
ImplicitFieldSchema,
ReadSchema,
TreeView,
TreeViewConfiguration,
UnsafeUnknownSchema,
ViewableTree,
} from "../simple-tree/index.js";
import { SchematizingSimpleTreeView } from "./schematizingTreeView.js";
@ -622,8 +624,18 @@ export class TreeCheckout implements ITreeCheckoutFork {
}
}
// For the new TreeViewAlpha API
public viewWith<TRoot extends ImplicitFieldSchema | UnsafeUnknownSchema>(
config: TreeViewConfiguration<ReadSchema<TRoot>>,
): SchematizingSimpleTreeView<TRoot>;
// For the old TreeView API
public viewWith<TRoot extends ImplicitFieldSchema>(
config: TreeViewConfiguration<TRoot>,
): TreeView<TRoot>;
public viewWith<TRoot extends ImplicitFieldSchema | UnsafeUnknownSchema>(
config: TreeViewConfiguration<ReadSchema<TRoot>>,
): SchematizingSimpleTreeView<TRoot> {
const view = new SchematizingSimpleTreeView(
this,

Просмотреть файл

@ -13,12 +13,13 @@ import {
type ImplicitFieldSchema,
type InsertableField,
type InsertableTreeFieldFromImplicitField,
type ReadableField,
type ReadSchema,
type TreeFieldFromImplicitField,
type TreeLeafValue,
type UnsafeUnknownSchema,
FieldKind,
} from "../schemaTypes.js";
import { NodeKind, type TreeNode, type TreeNodeSchema } from "../core/index.js";
import { NodeKind, type TreeNodeSchema } from "../core/index.js";
import { toStoredSchema } from "../toStoredSchema.js";
import { LeafNodeSchema } from "../leafNodeSchema.js";
import { assert } from "@fluidframework/core-utils/internal";
@ -434,13 +435,8 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
*/
export interface TreeViewAlpha<
in out TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema,
> extends Omit<
TreeView<TSchema extends ImplicitFieldSchema ? TSchema : ImplicitFieldSchema>,
"root" | "initialize"
> {
get root(): TSchema extends ImplicitFieldSchema
? TreeFieldFromImplicitField<TSchema>
: TreeLeafValue | TreeNode;
> extends Omit<TreeView<ReadSchema<TSchema>>, "root" | "initialize"> {
get root(): ReadableField<TSchema>;
set root(newRoot: InsertableField<TSchema>);

Просмотреть файл

@ -124,6 +124,8 @@ export {
type ApplyKindInput,
type InsertableTreeNodeFromAllowedTypes,
type Input,
type ReadableField,
type ReadSchema,
} from "./schemaTypes.js";
export {
getTreeNodeForField,

Просмотреть файл

@ -492,6 +492,33 @@ export type InsertableField<TSchema extends ImplicitFieldSchema | UnsafeUnknownS
? InsertableContent | undefined
: never;
/**
* Content which could be read from a field within a tree.
*
* @remarks
* Extended version of {@link TreeFieldFromImplicitField} that also allows {@link (UnsafeUnknownSchema:type)}.
* Since reading from fields with non-exact schema is still safe, this is only useful (compared to {@link TreeFieldFromImplicitField}) when the schema is also used as input and thus allows {@link (UnsafeUnknownSchema:type)}
* for use
* @system @alpha
*/
export type ReadableField<TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> =
TSchema extends ImplicitFieldSchema
? TreeFieldFromImplicitField<TSchema>
: TreeLeafValue | TreeNode;
/**
* Adapter to remove {@link (UnsafeUnknownSchema:type)} from a schema type so it can be used with types for generating APIs for reading data.
*
* @remarks
* Since reading with non-exact schema is still safe, this is mainly useful when the schema is also used as input and thus allows {@link (UnsafeUnknownSchema:type)}.
* @system @alpha
*/
export type ReadSchema<TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> = [
TSchema,
] extends [ImplicitFieldSchema]
? TSchema
: ImplicitFieldSchema;
/**
* Suitable for output.
* For input must error on side of excluding undefined instead.

Просмотреть файл

@ -21,7 +21,7 @@ import { MockTreeCheckout, forestWithContent } from "../../utils.js";
import {
toStoredSchema,
type ImplicitFieldSchema,
type InsertableTreeFieldFromImplicitField,
type InsertableField,
} from "../../../simple-tree/index.js";
export function getReadonlyContext(
@ -70,7 +70,7 @@ export interface TreeSimpleContentTyped<T extends ImplicitFieldSchema> {
* Default tree content to initialize the tree with iff the tree is uninitialized
* (meaning it does not even have any schema set at all).
*/
readonly initialTree: InsertableTreeFieldFromImplicitField<T>;
readonly initialTree: InsertableField<T>;
}
/**

Просмотреть файл

@ -46,7 +46,11 @@ import {
} from "../../index.js";
// eslint-disable-next-line import/no-internal-modules
import { SchematizingSimpleTreeView } from "../../shared-tree/schematizingTreeView.js";
import { getOrCreateInnerNode, toStoredSchema } from "../../simple-tree/index.js";
import {
getOrCreateInnerNode,
toStoredSchema,
type InsertableField,
} from "../../simple-tree/index.js";
// eslint-disable-next-line import/no-internal-modules
import { stringSchema } from "../../simple-tree/leafNodeSchema.js";
@ -1274,7 +1278,7 @@ function itView(
},
): void;
function itView<
T extends InsertableTreeFieldFromImplicitField<TRootSchema>,
T extends InsertableField<TRootSchema>,
TRootSchema extends ImplicitFieldSchema = typeof rootArray,
>(
title: string,

Просмотреть файл

@ -83,17 +83,17 @@ export class SharedTreeBranchManager {
nodeIdAttributeName?: string;
});
applyDiff(diff: Difference, objectToUpdate: Record<string, unknown> | TreeArrayNode): boolean;
checkoutNewMergedBranch<T extends ImplicitFieldSchema>(treeView: TreeView<T>, treeViewConfiguration: TreeViewConfiguration<T>, absolutePathToObjectNode: ObjectPath, llmResponse: Record<string, unknown> | unknown[]): {
checkoutNewMergedBranch<T extends ImplicitFieldSchema>(treeView: TreeViewAlpha<T>, treeViewConfiguration: TreeViewConfiguration<T>, absolutePathToObjectNode: ObjectPath, llmResponse: Record<string, unknown> | unknown[]): {
differences: Difference[];
originalBranch: TreeBranch;
forkBranch: TreeBranchFork;
forkView: TreeView<T>;
forkView: TreeViewAlpha<T>;
newBranchTargetNode: Record<string, unknown> | TreeArrayNode;
};
checkoutNewMergedBranchV2<T extends ImplicitFieldSchema>(treeView: TreeView<T>, treeViewConfiguration: TreeViewConfiguration<T>, absolutePathToObjectNode: ObjectPath): {
checkoutNewMergedBranchV2<T extends ImplicitFieldSchema>(treeView: TreeViewAlpha<T>, treeViewConfiguration: TreeViewConfiguration<T>, absolutePathToObjectNode: ObjectPath): {
originalBranch: TreeBranch;
forkBranch: TreeBranchFork;
forkView: TreeView<T>;
forkView: TreeViewAlpha<T>;
newBranchTargetNode: Record<string, unknown> | TreeArrayNode;
};
compare(obj: Record<string, unknown> | TreeArrayNode, newObj: Record<string, unknown> | unknown[]): Difference[];

Просмотреть файл

@ -7,11 +7,15 @@ import type {
ImplicitFieldSchema,
TreeArrayNode,
TreeMapNode,
TreeView,
TreeViewConfiguration,
} from "@fluidframework/tree";
// eslint-disable-next-line import/no-internal-modules -- This package depends on the branching APIs in Tree which are currently alpha
import { getBranch, type TreeBranch, type TreeBranchFork } from "@fluidframework/tree/alpha";
import {
getBranch,
type TreeBranch,
type TreeBranchFork,
type TreeViewAlpha,
// eslint-disable-next-line import/no-internal-modules -- This package depends on the branching APIs in Tree which are currently alpha
} from "@fluidframework/tree/alpha";
import type { z } from "zod";
import {
@ -87,7 +91,7 @@ export class SharedTreeBranchManager {
* produces a diff between two objects and merges the differences.
*/
public checkoutNewMergedBranch<T extends ImplicitFieldSchema>(
treeView: TreeView<T>,
treeView: TreeViewAlpha<T>,
treeViewConfiguration: TreeViewConfiguration<T>,
absolutePathToObjectNode: ObjectPath,
llmResponse: Record<string, unknown> | unknown[],
@ -95,12 +99,12 @@ export class SharedTreeBranchManager {
differences: Difference[];
originalBranch: TreeBranch;
forkBranch: TreeBranchFork;
forkView: TreeView<T>;
forkView: TreeViewAlpha<T>;
newBranchTargetNode: Record<string, unknown> | TreeArrayNode;
} {
const originalBranch = getBranch(treeView);
const forkBranch = originalBranch.branch();
const forkView = forkBranch.viewWith(treeViewConfiguration);
const forkView = forkBranch.viewWith(treeViewConfiguration) as TreeViewAlpha<T>;
console.log("traveling to absolute path from root:", absolutePathToObjectNode);
const newBranchTargetNode = sharedTreeTraverse(
@ -127,19 +131,19 @@ export class SharedTreeBranchManager {
* Creates a forked branch of a tree view.
*/
public checkoutNewMergedBranchV2<T extends ImplicitFieldSchema>(
treeView: TreeView<T>,
treeView: TreeViewAlpha<T>,
treeViewConfiguration: TreeViewConfiguration<T>,
absolutePathToObjectNode: ObjectPath,
// differences: Difference[],
): {
originalBranch: TreeBranch;
forkBranch: TreeBranchFork;
forkView: TreeView<T>;
forkView: TreeViewAlpha<T>;
newBranchTargetNode: Record<string, unknown> | TreeArrayNode;
} {
const originalBranch = getBranch(treeView);
const forkBranch = originalBranch.branch();
const forkView = forkBranch.viewWith(treeViewConfiguration);
const forkView = forkBranch.viewWith(treeViewConfiguration) as TreeViewAlpha<T>;
const newBranchTargetNode = sharedTreeTraverse(
forkView.root as TreeMapNode | TreeArrayNode | Record<string, unknown>,
absolutePathToObjectNode,

Просмотреть файл

@ -204,7 +204,7 @@ export enum ForestType {
export function getBranch(tree: ITree): TreeBranch;
// @alpha
export function getBranch<T extends ImplicitFieldSchema>(view: TreeView<T>): TreeBranch;
export function getBranch<T extends ImplicitFieldSchema | UnsafeUnknownSchema>(view: TreeViewAlpha<T>): TreeBranch;
// @alpha
export function getJsonSchema(schema: ImplicitFieldSchema): JsonTreeSchema;
@ -795,6 +795,9 @@ export type Off = () => void;
// @alpha
export type PopUnion<Union, AsOverloadedFunction = UnionToIntersection<Union extends unknown ? (f: Union) => void : never>> = AsOverloadedFunction extends (a: infer First) => void ? First : never;
// @alpha
export type ReadableField<TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> = TSchema extends ImplicitFieldSchema ? TreeFieldFromImplicitField<TSchema> : TreeLeafValue | TreeNode;
// @public @sealed
export interface ReadonlyArrayNode<out T = TreeNode | TreeLeafValue> extends ReadonlyArray<T>, Awaited<TreeNode & WithType<string, NodeKind.Array>> {
}
@ -815,6 +818,11 @@ interface ReadonlyMapInlined<K, T extends Unenforced<ImplicitAllowedTypes>> {
values(): IterableIterator<TreeNodeFromImplicitAllowedTypesUnsafe<T>>;
}
// @alpha
export type ReadSchema<TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> = [
TSchema
] extends [ImplicitFieldSchema] ? TSchema : ImplicitFieldSchema;
// @public
export type ReplaceIEventThisPlaceHolder<L extends any[], TThis> = L extends any[] ? {
[K in keyof L]: L[K] extends IEventThisPlaceHolder ? TThis : L[K];
@ -1168,11 +1176,11 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
}
// @alpha
export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> extends Omit<TreeView<TSchema extends ImplicitFieldSchema ? TSchema : ImplicitFieldSchema>, "root" | "initialize"> {
export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> extends Omit<TreeView<ReadSchema<TSchema>>, "root" | "initialize"> {
// (undocumented)
initialize(content: InsertableField<TSchema>): void;
// (undocumented)
get root(): TSchema extends ImplicitFieldSchema ? TreeFieldFromImplicitField<TSchema> : TreeLeafValue | TreeNode;
get root(): ReadableField<TSchema>;
set root(newRoot: InsertableField<TSchema>);
}