Skip to content

Commit

Permalink
tree: Reduce tree stable/public API surface using InternalTypes (#21482)
Browse files Browse the repository at this point in the history
## Description

Move several types into InternalTypes

The stable public API surface for Tree has been reduced.

## Breaking Changes

Several types have been moved into InternalTypes, indicating that they
are not fully stable nor intended to be referenced by users of Tree.

-   NodeBuilderData
-   FieldHasDefault
-   TreeNodeSchemaNonClass
-   TreeArrayNodeBase
-   ScopedSchemaName
-   DefaultProvider
-   typeNameSymbol
-   InsertableObjectFromSchemaRecord
-   ObjectFromSchemaRecord
-   FieldHasDefaultUnsafe

-   ObjectFromSchemaRecordUnsafe
-   TreeObjectNodeUnsafe
-   TreeFieldFromImplicitFieldUnsafe
-   TreeNodeFromImplicitAllowedTypesUnsafe
-   InsertableTreeNodeFromImplicitAllowedTypesUnsafe
-   TreeArrayNodeUnsafe
-   TreeMapNodeUnsafe
-   InsertableObjectFromSchemaRecordUnsafe
-   InsertableTreeFieldFromImplicitFieldUnsafe
-   InsertableTypedNodeUnsafe
-   NodeBuilderDataUnsafe
-   NodeFromSchemaUnsafe
-   FlexList
-   TreeApi

Additionally a few more types which could not be moved due to
technically limitations have been documented that they should be treated
similarly.

-   TreeNodeApi
-   TreeNodeSchemaCore
-   All \*Unsafe type (use for construction of recursive schema).
-   WithType
-   AllowedTypes
-   FieldSchemaUnsafe

Also to reduce confusion `type` was renamed to `typeNameSymbol`, and is
now only type exported. `Tree.is` should be used to get type information
from `TreeNodes` instead.
  • Loading branch information
CraigMacomber authored Jun 18, 2024
1 parent a9cc448 commit 64d49dd
Show file tree
Hide file tree
Showing 22 changed files with 530 additions and 192 deletions.
45 changes: 45 additions & 0 deletions .changeset/public-rabbits-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
"fluid-framework": minor
"@fluidframework/tree": minor
---

Move several types into InternalTypes

The stable public API surface for Tree has been reduced.
Several types have been moved into InternalTypes, indicating that they are not fully stable nor intended to be referenced by users of Tree.

- NodeBuilderData
- FieldHasDefault
- TreeNodeSchemaNonClass
- TreeArrayNodeBase
- ScopedSchemaName
- DefaultProvider
- typeNameSymbol
- InsertableObjectFromSchemaRecord
- ObjectFromSchemaRecord
- FieldHasDefaultUnsafe
- ObjectFromSchemaRecordUnsafe
- TreeObjectNodeUnsafe
- TreeFieldFromImplicitFieldUnsafe
- TreeNodeFromImplicitAllowedTypesUnsafe
- InsertableTreeNodeFromImplicitAllowedTypesUnsafe
- TreeArrayNodeUnsafe
- TreeMapNodeUnsafe
- InsertableObjectFromSchemaRecordUnsafe
- InsertableTreeFieldFromImplicitFieldUnsafe
- InsertableTypedNodeUnsafe
- NodeBuilderDataUnsafe
- NodeFromSchemaUnsafe
- FlexList
- TreeApi

Additionally a few more types which could not be moved due to technically limitations have been documented that they should be treated similarly.

- TreeNodeApi
- TreeNodeSchemaCore
- All \*Unsafe type (use for construction of recursive schema).
- WithType
- AllowedTypes
- FieldSchemaUnsafe

Also to reduce confusion `type` was renamed to `typeNameSymbol`, and is now only type exported. `Tree.is` should be used to get type information from `TreeNodes` instead.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*!
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/

// This file is full of test exports to ensure the types can be exported, not actually thing anyone will import.
/* eslint-disable jsdoc/require-jsdoc */

import {
SchemaFactory,
TreeViewConfiguration,
type NodeFromSchema,
type ValidateRecursiveSchema,
// To diagnose `error TS2742: The inferred type of ...` errors,
// enable this import then look for use of it in the generated d.ts file fo find what needs to be moved out of InternalTypes
// eslint-disable-next-line unused-imports/no-unused-imports
// InternalTypes,
} from "@fluidframework/tree";

// Due to limitation of the TypeScript compiler, errors like the following can be produced when exporting types from another package:
// error TS2742: The inferred type of 'Inventory' cannot be named without a reference to '../node_modules/@fluidframework/tree/lib/internalTypes.js'. This is likely not portable. A type annotation is necessary.
// Tree needs tests to make sure it does not trigger such errors, but they can't easily be done from within the tree package.
// Thus tests for this case are included here, in a package which uses tree.

export const schema = new SchemaFactory("com.example");

export const leafAlias = schema.number;

export class Point extends schema.object("Point", {
x: schema.number,
}) {}

export class Note extends schema.object("Note", {
text: schema.string,
location: schema.optional(Point),
}) {}

export class NodeMap extends schema.map("NoteMap", Note) {}
export class NodeList extends schema.array("NoteList", Note) {}

export class Canvas extends schema.object("Canvas", { stuff: [NodeMap, NodeList] }) {}

export const POJO = schema.object("POJO", { stuff: [NodeMap, NodeList] });
export type POJO = NodeFromSchema<typeof POJO>;

export const config = new TreeViewConfiguration({ schema: Canvas });

// Recursive cases
// This lint rule doesn't work well with our schema when using the lazy format
/* eslint-disable @typescript-eslint/explicit-function-return-type */

export class RecursiveObject extends schema.objectRecursive("RO", {
x: [() => RecursiveObject, schema.number],
}) {}
{
type _check = ValidateRecursiveSchema<typeof RecursiveObject>;
}

export const recursiveField = schema.optionalRecursive([() => RecursiveObject, schema.number]);

export class RecursiveMap extends schema.mapRecursive("RM", [() => RecursiveMap]) {}
{
type _check = ValidateRecursiveSchema<typeof RecursiveMap>;
}

export class RecursiveArray extends schema.arrayRecursive("RA", [() => RecursiveArray]) {}
{
type _check = ValidateRecursiveSchema<typeof RecursiveArray>;
}

/* eslint-enable @typescript-eslint/explicit-function-return-type */
4 changes: 4 additions & 0 deletions experimental/framework/tree-react-api/src/test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"rootDir": "./",
"outDir": "../../lib/test",
"types": ["mocha", "node"],
// Allows writing type checking expression without having to use the results.
"noUnusedLocals": false,
// Allow testing that declarations work properly
"declaration": true,
},
"include": ["./**/*"],
"references": [
Expand Down
70 changes: 48 additions & 22 deletions packages/dds/tree/api-report/tree.alpha.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ export interface CommitMetadata {
}

// @public
export interface DefaultProvider extends ErasedType<"@fluidframework/tree.FieldProvider"> {
interface DefaultProvider extends ErasedType<"@fluidframework/tree.FieldProvider"> {
}

// @public
type ExtractItemType<Item extends LazyItem> = Item extends () => infer Result ? Result : Item;

// @public
export type FieldHasDefault<T extends ImplicitFieldSchema> = T extends FieldSchema<FieldKind.Optional | FieldKind.Identifier> ? true : false;
type FieldHasDefault<T extends ImplicitFieldSchema> = T extends FieldSchema<FieldKind.Optional | FieldKind.Identifier> ? true : false;

// @public
export type FieldHasDefaultUnsafe<T extends Unenforced<ImplicitFieldSchema>> = T extends FieldSchemaUnsafe<FieldKind.Optional | FieldKind.Identifier, Unenforced<ImplicitAllowedTypes>> ? true : false;
type FieldHasDefaultUnsafe<T extends Unenforced<ImplicitFieldSchema>> = T extends FieldSchemaUnsafe<FieldKind.Optional | FieldKind.Identifier, Unenforced<ImplicitAllowedTypes>> ? true : false;

// @public
export enum FieldKind {
Expand Down Expand Up @@ -87,7 +87,7 @@ type FlattenKeys<T> = [{
}][_InlineTrick];

// @public
export type FlexList<Item = unknown> = readonly LazyItem<Item>[];
type FlexList<Item = unknown> = readonly LazyItem<Item>[];

// @public
type FlexListToUnion<TList extends FlexList> = ExtractItemType<TList[number]>;
Expand All @@ -102,7 +102,7 @@ export type ImplicitFieldSchema = FieldSchema | ImplicitAllowedTypes;
type _InlineTrick = 0;

// @public
export type InsertableObjectFromSchemaRecord<T extends RestrictiveReadonlyRecord<string, ImplicitFieldSchema>> = FlattenKeys<{
type InsertableObjectFromSchemaRecord<T extends RestrictiveReadonlyRecord<string, ImplicitFieldSchema>> = FlattenKeys<{
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property]>;
} & {
readonly [Property in keyof T as FieldHasDefault<T[Property]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property]>;
Expand Down Expand Up @@ -133,9 +133,11 @@ export type InsertableTypedNode<T extends TreeNodeSchema> = (T extends {
} ? NodeBuilderData<T> : never) | Unhydrated<NodeFromSchema<T>>;

// @public
export type InsertableTypedNodeUnsafe<T extends Unenforced<TreeNodeSchema>> = Unhydrated<NodeFromSchemaUnsafe<T>> | (T extends {
type InsertableTypedNodeUnsafe<T extends Unenforced<TreeNodeSchema>> = [
Unhydrated<NodeFromSchemaUnsafe<T>> | (T extends {
implicitlyConstructable: true;
} ? NodeBuilderDataUnsafe<T> : never);
} ? NodeBuilderDataUnsafe<T> : never)
][_InlineTrick];

// @public
export interface InternalTreeNode extends ErasedType<"@fluidframework/tree.InternalTreeNode"> {
Expand All @@ -146,8 +148,32 @@ declare namespace InternalTypes {
_InlineTrick,
FlattenKeys,
ApplyKind,
NodeBuilderData,
FieldHasDefault,
TreeNodeSchemaNonClass,
TreeArrayNodeBase,
ScopedSchemaName,
DefaultProvider,
typeNameSymbol_2 as typeNameSymbol,
InsertableObjectFromSchemaRecord,
ObjectFromSchemaRecord,
FieldHasDefaultUnsafe,
ObjectFromSchemaRecordUnsafe,
TreeObjectNodeUnsafe,
TreeFieldFromImplicitFieldUnsafe,
TreeNodeFromImplicitAllowedTypesUnsafe,
InsertableTreeNodeFromImplicitAllowedTypesUnsafe,
TreeArrayNodeUnsafe,
TreeMapNodeUnsafe,
InsertableObjectFromSchemaRecordUnsafe,
InsertableTreeFieldFromImplicitFieldUnsafe,
InsertableTypedNodeUnsafe,
NodeBuilderDataUnsafe,
NodeFromSchemaUnsafe,
FlexList,
FlexListToUnion,
ExtractItemType
ExtractItemType,
TreeApi
}
}
export { InternalTypes }
Expand Down Expand Up @@ -194,16 +220,16 @@ export interface MakeNominal {
}

// @public
export type NodeBuilderData<T extends TreeNodeSchema> = T extends TreeNodeSchema<string, NodeKind, unknown, infer TBuild> ? TBuild : never;
type NodeBuilderData<T extends TreeNodeSchema> = T extends TreeNodeSchema<string, NodeKind, unknown, infer TBuild> ? TBuild : never;

// @public
export type NodeBuilderDataUnsafe<T extends Unenforced<TreeNodeSchema>> = T extends TreeNodeSchema<string, NodeKind, unknown, infer TBuild> ? TBuild : never;
type NodeBuilderDataUnsafe<T extends Unenforced<TreeNodeSchema>> = T extends TreeNodeSchema<string, NodeKind, unknown, infer TBuild> ? TBuild : never;

// @public
export type NodeFromSchema<T extends TreeNodeSchema> = T extends TreeNodeSchema<string, NodeKind, infer TNode> ? TNode : never;

// @public
export type NodeFromSchemaUnsafe<T extends Unenforced<TreeNodeSchema>> = T extends TreeNodeSchema<string, NodeKind, infer TNode> ? TNode : never;
type NodeFromSchemaUnsafe<T extends Unenforced<TreeNodeSchema>> = T extends TreeNodeSchema<string, NodeKind, infer TNode> ? TNode : never;

// @public
export interface NodeInDocumentConstraint {
Expand All @@ -222,12 +248,12 @@ export enum NodeKind {
}

// @public
export type ObjectFromSchemaRecord<T extends RestrictiveReadonlyRecord<string, ImplicitFieldSchema>> = {
type ObjectFromSchemaRecord<T extends RestrictiveReadonlyRecord<string, ImplicitFieldSchema>> = {
-readonly [Property in keyof T]: TreeFieldFromImplicitField<T[Property]>;
};

// @public
export type ObjectFromSchemaRecordUnsafe<T extends Unenforced<RestrictiveReadonlyRecord<string, ImplicitFieldSchema>>> = {
type ObjectFromSchemaRecordUnsafe<T extends Unenforced<RestrictiveReadonlyRecord<string, ImplicitFieldSchema>>> = {
-readonly [Property in keyof T]: TreeFieldFromImplicitFieldUnsafe<T[Property]>;
};

Expand Down Expand Up @@ -321,7 +347,7 @@ export class SchemaFactory<out TScope extends string | undefined = string | unde
}

// @public
export type ScopedSchemaName<TScope extends string | undefined, TName extends number | string> = TScope extends undefined ? `${TName}` : `${TScope}.${TName}`;
type ScopedSchemaName<TScope extends string | undefined, TName extends number | string> = TScope extends undefined ? `${TName}` : `${TScope}.${TName}`;

// @alpha
export const SharedTree: ISharedObjectKind<ITree> & SharedObjectKind<ITree>;
Expand All @@ -333,7 +359,7 @@ export type TransactionConstraint = NodeInDocumentConstraint;
export const Tree: TreeApi;

// @public
export interface TreeApi extends TreeNodeApi {
interface TreeApi extends TreeNodeApi {
contains(node: TreeNode, other: TreeNode): boolean;
readonly runTransaction: RunTransaction;
}
Expand All @@ -348,7 +374,7 @@ export const TreeArrayNode: {
};

// @public
export interface TreeArrayNodeBase<out T, in TNew, in TMoveFrom> extends ReadonlyArray<T>, TreeNode {
interface TreeArrayNodeBase<out T, in TNew, in TMoveFrom> extends ReadonlyArray<T>, TreeNode {
insertAt(index: number, ...value: readonly (TNew | IterableTreeArrayContent<TNew>)[]): void;
insertAtEnd(...value: readonly (TNew | IterableTreeArrayContent<TNew>)[]): void;
insertAtStart(...value: readonly (TNew | IterableTreeArrayContent<TNew>)[]): void;
Expand Down Expand Up @@ -382,7 +408,7 @@ export interface TreeChangeEvents {
export type TreeFieldFromImplicitField<TSchema extends ImplicitFieldSchema = FieldSchema> = TSchema extends FieldSchema<infer Kind, infer Types> ? ApplyKind<TreeNodeFromImplicitAllowedTypes<Types>, Kind, false> : TSchema extends ImplicitAllowedTypes ? TreeNodeFromImplicitAllowedTypes<TSchema> : unknown;

// @public
export type TreeFieldFromImplicitFieldUnsafe<TSchema extends Unenforced<ImplicitFieldSchema>> = TSchema extends FieldSchemaUnsafe<infer Kind, infer Types> ? ApplyKind<TreeNodeFromImplicitAllowedTypesUnsafe<Types>, Kind, false> : TSchema extends ImplicitAllowedTypes ? TreeNodeFromImplicitAllowedTypesUnsafe<TSchema> : unknown;
type TreeFieldFromImplicitFieldUnsafe<TSchema extends Unenforced<ImplicitFieldSchema>> = TSchema extends FieldSchemaUnsafe<infer Kind, infer Types> ? ApplyKind<TreeNodeFromImplicitAllowedTypesUnsafe<Types>, Kind, false> : TSchema extends ImplicitAllowedTypes ? TreeNodeFromImplicitAllowedTypesUnsafe<TSchema> : unknown;

// @public
export type TreeLeafValue = number | string | boolean | IFluidHandle | null;
Expand All @@ -407,7 +433,7 @@ export interface TreeMapNodeUnsafe<T extends Unenforced<ImplicitAllowedTypes>> e
export abstract class TreeNode implements WithType {
static [Symbol.hasInstance](value: unknown): value is TreeNode;
static [Symbol.hasInstance]<TSchema extends abstract new (...args: any[]) => TreeNode>(this: TSchema, value: unknown): value is InstanceType<TSchema>;
abstract get [type](): string;
abstract get [typeNameSymbol_2](): string;
protected constructor();
}

Expand All @@ -426,7 +452,7 @@ export interface TreeNodeApi {
export type TreeNodeFromImplicitAllowedTypes<TSchema extends ImplicitAllowedTypes = TreeNodeSchema> = TSchema extends TreeNodeSchema ? NodeFromSchema<TSchema> : TSchema extends AllowedTypes ? NodeFromSchema<FlexListToUnion<TSchema>> : unknown;

// @public
export type TreeNodeFromImplicitAllowedTypesUnsafe<TSchema extends Unenforced<ImplicitAllowedTypes>> = TSchema extends ImplicitAllowedTypes ? TreeNodeFromImplicitAllowedTypes<TSchema> : TSchema extends TreeNodeSchema ? NodeFromSchema<TSchema> : TSchema extends AllowedTypes ? NodeFromSchema<FlexListToUnion<TSchema>> : unknown;
type TreeNodeFromImplicitAllowedTypesUnsafe<TSchema extends Unenforced<ImplicitAllowedTypes>> = TSchema extends ImplicitAllowedTypes ? TreeNodeFromImplicitAllowedTypes<TSchema> : TSchema extends TreeNodeSchema ? NodeFromSchema<TSchema> : TSchema extends AllowedTypes ? NodeFromSchema<FlexListToUnion<TSchema>> : unknown;

// @public
export type TreeNodeSchema<Name extends string = string, Kind extends NodeKind = NodeKind, TNode = unknown, TBuild = never, ImplicitlyConstructable extends boolean = boolean, Info = unknown> = TreeNodeSchemaClass<Name, Kind, TNode, TBuild, ImplicitlyConstructable, Info> | TreeNodeSchemaNonClass<Name, Kind, TNode, TBuild, ImplicitlyConstructable, Info>;
Expand All @@ -448,7 +474,7 @@ export interface TreeNodeSchemaCore<out Name extends string, out Kind extends No
}

// @public
export interface TreeNodeSchemaNonClass<out Name extends string = string, out Kind extends NodeKind = NodeKind, out TNode = unknown, in TInsertable = never, out ImplicitlyConstructable extends boolean = boolean, out Info = unknown> extends TreeNodeSchemaCore<Name, Kind, ImplicitlyConstructable, Info> {
interface TreeNodeSchemaNonClass<out Name extends string = string, out Kind extends NodeKind = NodeKind, out TNode = unknown, in TInsertable = never, out ImplicitlyConstructable extends boolean = boolean, out Info = unknown> extends TreeNodeSchemaCore<Name, Kind, ImplicitlyConstructable, Info> {
// (undocumented)
create(data: TInsertable): TNode;
}
Expand Down Expand Up @@ -492,7 +518,7 @@ export interface TreeViewEvents {
}

// @public
export const type: unique symbol;
const typeNameSymbol_2: unique symbol;

// @public
export type Unenforced<_DesiredExtendsConstraint> = unknown;
Expand All @@ -513,7 +539,7 @@ export type ValidateRecursiveSchema<T extends TreeNodeSchemaClass<string, NodeKi

// @public
export interface WithType<TName extends string = string> {
get [type](): TName;
get [typeNameSymbol_2](): TName;
}

// (No @packageDocumentation comment for this package)
Expand Down
Loading

0 comments on commit 64d49dd

Please sign in to comment.