tree: Cleanup related to contravariant input types (#22875)
## Description Misc improvements found when working on https://github.com/microsoft/FluidFramework/pull/22874 . Many of these are places where schema types were not captured properly, or incorrect typing wasn't detected due to the incorrect variance. ## Breaking Changes The change to `InsertableObjectFromSchemaRecord` could impact something: it's strictly a bug fix but its unclear what implications its wrong version could have. I suspect no realistic code would be broken by these more correct types, but it's possible something could be impacted.
This commit is contained in:
Родитель
b8e887ead4
Коммит
7405cf5ad2
|
@ -22,6 +22,7 @@
|
|||
"endregion",
|
||||
"insertable",
|
||||
"reentrantly",
|
||||
"typeparam",
|
||||
"unhydrated",
|
||||
],
|
||||
|
||||
|
|
|
@ -173,9 +173,9 @@ export type InsertableField<TSchema extends ImplicitFieldSchema | UnsafeUnknownS
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -771,7 +771,7 @@ export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | Unsa
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
|
@ -103,9 +103,9 @@ type _InlineTrick = 0;
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -564,7 +564,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
|
@ -103,9 +103,9 @@ type _InlineTrick = 0;
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -551,7 +551,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
|
@ -103,9 +103,9 @@ type _InlineTrick = 0;
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -548,7 +548,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
|
@ -103,9 +103,9 @@ type _InlineTrick = 0;
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -548,7 +548,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
|
@ -144,7 +144,7 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
|
|||
|
||||
this.runSchemaEdit(() => {
|
||||
const mapTree = mapTreeFromNodeData(
|
||||
content as InsertableContent,
|
||||
content as InsertableContent | undefined,
|
||||
this.rootFieldSchema,
|
||||
this.nodeKeyManager,
|
||||
{
|
||||
|
@ -359,7 +359,11 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
|
|||
);
|
||||
}
|
||||
const view = this.getView();
|
||||
setField(view.context.root, this.rootFieldSchema, newRoot as InsertableContent);
|
||||
setField(
|
||||
view.context.root,
|
||||
this.rootFieldSchema,
|
||||
newRoot as InsertableContent | undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,11 @@ import type { ITreeCursorSynchronous, SchemaAndPolicy } from "../../core/index.j
|
|||
import type {
|
||||
TreeLeafValue,
|
||||
ImplicitFieldSchema,
|
||||
InsertableTreeFieldFromImplicitField,
|
||||
TreeFieldFromImplicitField,
|
||||
FieldSchema,
|
||||
FieldKind,
|
||||
UnsafeUnknownSchema,
|
||||
InsertableField,
|
||||
} from "../schemaTypes.js";
|
||||
import {
|
||||
getOrCreateNodeFromInnerNode,
|
||||
|
@ -29,7 +30,7 @@ import {
|
|||
} from "../../feature-libraries/index.js";
|
||||
import { isFieldInSchema } from "../../feature-libraries/index.js";
|
||||
import { toStoredSchema } from "../toFlexSchema.js";
|
||||
import { inSchemaOrThrow, mapTreeFromNodeData, type InsertableContent } from "../toMapTree.js";
|
||||
import { inSchemaOrThrow, mapTreeFromNodeData } from "../toMapTree.js";
|
||||
import {
|
||||
applySchemaToParserOptions,
|
||||
cursorFromVerbose,
|
||||
|
@ -55,7 +56,7 @@ import { getUnhydratedContext } from "../createContext.js";
|
|||
*/
|
||||
export function createFromInsertable<TSchema extends ImplicitFieldSchema>(
|
||||
schema: TSchema,
|
||||
data: InsertableTreeFieldFromImplicitField<TSchema>,
|
||||
data: InsertableField<TSchema>,
|
||||
context?: NodeKeyManager | undefined,
|
||||
): Unhydrated<TreeFieldFromImplicitField<TSchema>> {
|
||||
const cursor = cursorFromInsertable(schema, data, context);
|
||||
|
@ -72,9 +73,13 @@ export function createFromInsertable<TSchema extends ImplicitFieldSchema>(
|
|||
* this is the same as invoking its constructor except that an unhydrated node can also be provided and the returned value is a cursor.
|
||||
* When `undefined` is provided (for an optional field), `undefined` is returned.
|
||||
*/
|
||||
export function cursorFromInsertable<TSchema extends ImplicitFieldSchema>(
|
||||
schema: TSchema,
|
||||
data: InsertableTreeFieldFromImplicitField<TSchema>,
|
||||
export function cursorFromInsertable<
|
||||
TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema,
|
||||
>(
|
||||
schema: UnsafeUnknownSchema extends TSchema
|
||||
? ImplicitFieldSchema
|
||||
: TSchema & ImplicitFieldSchema,
|
||||
data: InsertableField<TSchema>,
|
||||
context?: NodeKeyManager | undefined,
|
||||
):
|
||||
| ITreeCursorSynchronous
|
||||
|
@ -87,7 +92,7 @@ export function cursorFromInsertable<TSchema extends ImplicitFieldSchema>(
|
|||
};
|
||||
|
||||
const mapTree = mapTreeFromNodeData(
|
||||
data as InsertableContent | undefined,
|
||||
data as InsertableField<UnsafeUnknownSchema>,
|
||||
schema,
|
||||
context,
|
||||
schemaValidationPolicy,
|
||||
|
|
|
@ -193,8 +193,9 @@ export interface ITreeViewConfiguration<
|
|||
* Configuration for {@link ViewableTree.viewWith}.
|
||||
* @sealed @public
|
||||
*/
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema>
|
||||
implements Required<ITreeViewConfiguration<TSchema>>
|
||||
export class TreeViewConfiguration<
|
||||
const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema,
|
||||
> implements Required<ITreeViewConfiguration<TSchema>>
|
||||
{
|
||||
protected _typeCheck!: MakeNominal;
|
||||
|
||||
|
|
|
@ -12,7 +12,11 @@ import {
|
|||
type Unhydrated,
|
||||
type WithType,
|
||||
} from "../core/index.js";
|
||||
import type { ImplicitFieldSchema, TreeFieldFromImplicitField } from "../schemaTypes.js";
|
||||
import type {
|
||||
ImplicitFieldSchema,
|
||||
TreeFieldFromImplicitField,
|
||||
UnsafeUnknownSchema,
|
||||
} from "../schemaTypes.js";
|
||||
import { treeNodeApi } from "./treeNodeApi.js";
|
||||
import { createFromCursor, cursorFromInsertable } from "./create.js";
|
||||
import type { ITreeCursorSynchronous } from "../../core/index.js";
|
||||
|
@ -145,7 +149,7 @@ export const TreeBeta: {
|
|||
if (!kernel.isHydrated()) {
|
||||
return createFromCursor(
|
||||
kernel.schema,
|
||||
cursorFromInsertable(kernel.schema, node),
|
||||
cursorFromInsertable<UnsafeUnknownSchema>(kernel.schema, node),
|
||||
) as Unhydrated<TreeFieldFromImplicitField<TSchema>>;
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,10 @@ export interface TreeMapNode<T extends ImplicitAllowedTypes = ImplicitAllowedTyp
|
|||
): void;
|
||||
}
|
||||
|
||||
const handler: ProxyHandler<TreeMapNode> = {
|
||||
// TreeMapNode is invariant over schema type, so for this handler to work with all schema, the only possible type for the schema is `any`.
|
||||
// This is not ideal, but no alternatives are possible.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const handler: ProxyHandler<TreeMapNode<any>> = {
|
||||
getPrototypeOf: () => {
|
||||
return Map.prototype;
|
||||
},
|
||||
|
@ -177,7 +180,7 @@ abstract class CustomMapNodeBase<const T extends ImplicitAllowedTypes> extends T
|
|||
const node = this.innerNode;
|
||||
return node.keys();
|
||||
}
|
||||
public set(key: string, value: InsertableTreeNodeFromImplicitAllowedTypes<T>): TreeMapNode {
|
||||
public set(key: string, value: InsertableTreeNodeFromImplicitAllowedTypes<T>): this {
|
||||
const kernel = getKernel(this);
|
||||
const node = this.innerNode;
|
||||
const mapTree = mapTreeFromNodeData(
|
||||
|
@ -244,7 +247,7 @@ export function mapSchema<
|
|||
flexNode: FlexTreeNode,
|
||||
): TreeNodeValid<T2> {
|
||||
if (useMapPrototype) {
|
||||
return new Proxy<Schema>(instance as Schema, handler);
|
||||
return new Proxy<Schema>(instance as Schema, handler as ProxyHandler<Schema>);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
|
|
@ -107,13 +107,13 @@ export type InsertableObjectFromSchemaRecord<
|
|||
> = FlattenKeys<
|
||||
{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<
|
||||
T[Property] & string
|
||||
T[Property & string]
|
||||
>;
|
||||
} & {
|
||||
// Field does not have a known default, make it required:
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false
|
||||
? Property
|
||||
: never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
: never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}
|
||||
>;
|
||||
|
||||
|
|
|
@ -57,13 +57,13 @@ import {
|
|||
import {
|
||||
MockTreeCheckout,
|
||||
checkoutWithContent,
|
||||
cursorFromInsertableTreeField,
|
||||
forestWithContent,
|
||||
mintRevisionTag,
|
||||
testIdCompressor,
|
||||
type SharedTreeWithConnectionStateSetter,
|
||||
} from "../../utils.js";
|
||||
import {
|
||||
cursorFromInsertable,
|
||||
numberSchema,
|
||||
SchemaFactory,
|
||||
stringSchema,
|
||||
|
@ -108,7 +108,7 @@ class HasIdentifier extends schemaFactory.object("parent", {
|
|||
}) {}
|
||||
|
||||
function getIdentifierEncodingContext(id: string) {
|
||||
const initialTree = cursorFromInsertableTreeField(
|
||||
const initialTree = cursorFromInsertable(
|
||||
HasIdentifier,
|
||||
new HasIdentifier({ identifier: id }),
|
||||
new MockNodeKeyManager(),
|
||||
|
|
|
@ -13,17 +13,18 @@ import {
|
|||
// eslint-disable-next-line import/no-internal-modules
|
||||
} from "../../shared-tree/schematizingTreeView.js";
|
||||
import {
|
||||
cursorFromInsertable,
|
||||
SchemaFactory,
|
||||
TreeViewConfiguration,
|
||||
type ImplicitFieldSchema,
|
||||
type InsertableTreeFieldFromImplicitField,
|
||||
type InsertableField,
|
||||
type UnsafeUnknownSchema,
|
||||
} from "../../simple-tree/index.js";
|
||||
// eslint-disable-next-line import/no-internal-modules
|
||||
import { toStoredSchema } from "../../simple-tree/toFlexSchema.js";
|
||||
import {
|
||||
checkoutWithContent,
|
||||
createTestUndoRedoStacks,
|
||||
cursorFromInsertableTreeField,
|
||||
validateUsageError,
|
||||
} from "../utils.js";
|
||||
import { insert } from "../sequenceRootUtils.js";
|
||||
|
@ -40,10 +41,10 @@ const configGeneralized2 = new TreeViewConfiguration({
|
|||
|
||||
function checkoutWithInitialTree(
|
||||
viewConfig: TreeViewConfiguration,
|
||||
unhydratedInitialTree: InsertableTreeFieldFromImplicitField,
|
||||
unhydratedInitialTree: InsertableField<UnsafeUnknownSchema>,
|
||||
nodeKeyManager = new MockNodeKeyManager(),
|
||||
): TreeCheckout {
|
||||
const initialTree = cursorFromInsertableTreeField(
|
||||
const initialTree = cursorFromInsertable<UnsafeUnknownSchema>(
|
||||
viewConfig.schema,
|
||||
unhydratedInitialTree,
|
||||
nodeKeyManager,
|
||||
|
|
|
@ -76,7 +76,7 @@ describe("getJsonSchema", () => {
|
|||
|
||||
it("Union root", async () => {
|
||||
const schemaFactory = new SchemaFactory("test");
|
||||
const Schema = [schemaFactory.number, schemaFactory.string];
|
||||
const Schema = [schemaFactory.number, schemaFactory.string] as const;
|
||||
|
||||
const actual = getJsonSchema(Schema);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import {
|
|||
} from "../../core/index.js";
|
||||
import {
|
||||
booleanSchema,
|
||||
cursorFromInsertable,
|
||||
handleSchema,
|
||||
nullSchema,
|
||||
numberSchema,
|
||||
|
@ -59,7 +60,7 @@ import {
|
|||
MockNodeKeyManager,
|
||||
type NodeKeyManager,
|
||||
} from "../../feature-libraries/index.js";
|
||||
import { cursorFromInsertableTreeField, validateUsageError } from "../utils.js";
|
||||
import { validateUsageError } from "../utils.js";
|
||||
|
||||
/**
|
||||
* Helper for building {@link TreeFieldStoredSchema}.
|
||||
|
@ -1513,15 +1514,16 @@ describe("toMapTree", () => {
|
|||
new Map(),
|
||||
);
|
||||
|
||||
describe("cursorFromInsertableTreeField", () => {
|
||||
describe("cursorFromInsertable", () => {
|
||||
it("Success", () => {
|
||||
cursorFromInsertableTreeField(schemaFactory.string, "Hello world", nodeKeyManager);
|
||||
cursorFromInsertable(schemaFactory.string, "Hello world", nodeKeyManager);
|
||||
});
|
||||
|
||||
it("Failure", () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
cursorFromInsertableTreeField(schemaFactory.number, "Hello world", nodeKeyManager),
|
||||
// @ts-expect-error invalid data for schema
|
||||
cursorFromInsertable(schemaFactory.number, "Hello world", nodeKeyManager),
|
||||
validateUsageError(/incompatible/),
|
||||
);
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@ interface TestCaseErased {
|
|||
}
|
||||
|
||||
function test<T extends ImplicitFieldSchema>(t: TestCase<T>): TestCaseErased {
|
||||
return t;
|
||||
return t as TestCaseErased;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -170,7 +170,7 @@ describe("Primitives", () => {
|
|||
describe("with schema [_.number, _.null]", () => {
|
||||
// JSON coerces non-finite numbers to 'null'. This succeeds when 'null' is
|
||||
// permitted by schema.
|
||||
const schema = [schemaFactory.number, schemaFactory.null];
|
||||
const schema = [schemaFactory.number, schemaFactory.null] as const;
|
||||
[-Infinity, NaN, Infinity].forEach((value) => checkCoerced(schema, value));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
type WideTreeNode,
|
||||
} from "./benchmarkUtilities.js";
|
||||
import { SchemaFactory } from "../../simple-tree/index.js";
|
||||
import { hydrate } from "./utils.js";
|
||||
import { hydrate, hydrateUnsafe } from "./utils.js";
|
||||
|
||||
// number of nodes in test for wide trees
|
||||
const nodesCountWide = [
|
||||
|
@ -250,11 +250,11 @@ describe("SimpleTree benchmarks", () => {
|
|||
title: `Read value from union of leaf and non-leaf`,
|
||||
mapType: NumberObjectMap,
|
||||
},
|
||||
];
|
||||
] as const;
|
||||
|
||||
for (const { title, mapType } of valueTestCases) {
|
||||
const initUnhydrated = () => new mapType([["a", 1]]);
|
||||
const initFlex = () => hydrate(mapType, initUnhydrated());
|
||||
const initFlex = () => hydrateUnsafe(mapType, initUnhydrated());
|
||||
const readFunction = (tree: CombinedTypes) => tree.get("a") as number;
|
||||
generateBenchmarkPair(title, initUnhydrated, initFlex, readFunction, 1);
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ describe("SimpleTree benchmarks", () => {
|
|||
|
||||
for (const { title, mapType } of undefinedTestCases) {
|
||||
const initUnhydrated = () => new mapType([["a", 1]]);
|
||||
const initFlex = () => hydrate(mapType, initUnhydrated());
|
||||
const initFlex = () => hydrateUnsafe(mapType, initUnhydrated());
|
||||
const readFunction = (tree: CombinedTypes) => tree.get("b") as number;
|
||||
generateBenchmarkPair(title, initUnhydrated, initFlex, readFunction, undefined);
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ describe("SimpleTree benchmarks", () => {
|
|||
|
||||
for (const { title, arrayType } of testCases) {
|
||||
const initUnhydrated = () => new arrayType([1]);
|
||||
const initFlex = () => hydrate(arrayType, initUnhydrated());
|
||||
const initFlex = () => hydrateUnsafe(arrayType, initUnhydrated());
|
||||
const read = (tree: NumArray | NumStringArray | NumObjectArray) => tree[0] as number;
|
||||
generateBenchmarkPair(title, initUnhydrated, initFlex, read, 1);
|
||||
}
|
||||
|
|
|
@ -21,12 +21,14 @@ import {
|
|||
SimpleContextSlot,
|
||||
type ImplicitFieldSchema,
|
||||
type InsertableContent,
|
||||
type InsertableField,
|
||||
type InsertableTreeFieldFromImplicitField,
|
||||
type NodeKind,
|
||||
type TreeFieldFromImplicitField,
|
||||
type TreeLeafValue,
|
||||
type TreeNode,
|
||||
type TreeNodeSchema,
|
||||
type UnsafeUnknownSchema,
|
||||
} from "../../simple-tree/index.js";
|
||||
import {
|
||||
getTreeNodeForField,
|
||||
|
@ -114,7 +116,7 @@ export function describeHydration(
|
|||
*
|
||||
* TODO: determine and document if this produces "cooked" or "marinated" nodes.
|
||||
*/
|
||||
export function hydrate<TSchema extends ImplicitFieldSchema>(
|
||||
export function hydrate<const TSchema extends ImplicitFieldSchema>(
|
||||
schema: TSchema,
|
||||
initialTree: InsertableTreeFieldFromImplicitField<TSchema>,
|
||||
): TreeFieldFromImplicitField<TSchema> {
|
||||
|
@ -145,6 +147,18 @@ export function hydrate<TSchema extends ImplicitFieldSchema>(
|
|||
return getTreeNodeForField(field) as TreeFieldFromImplicitField<TSchema>;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link hydrate} but unsafe initialTree.
|
||||
* This may be required when the schema is not entirely statically typed, for example when looping over multiple test cases and thus using a imprecise schema type.
|
||||
* In such cases the "safe" version of hydrate may require `never` for the initial tree.
|
||||
*/
|
||||
export function hydrateUnsafe<const TSchema extends ImplicitFieldSchema>(
|
||||
schema: TSchema,
|
||||
initialTree: InsertableField<UnsafeUnknownSchema>,
|
||||
): TreeFieldFromImplicitField<TSchema> {
|
||||
return hydrate(schema, initialTree as InsertableTreeFieldFromImplicitField<TSchema>);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to JSON stringify, but allows `undefined` at the root and returns numbers as-is at the root.
|
||||
*/
|
||||
|
|
|
@ -35,7 +35,9 @@ import {
|
|||
stringSchema,
|
||||
toStoredSchema,
|
||||
type ImplicitFieldSchema,
|
||||
type InsertableField,
|
||||
type InsertableTreeFieldFromImplicitField,
|
||||
type UnsafeUnknownSchema,
|
||||
type ValidateRecursiveSchema,
|
||||
} from "../simple-tree/index.js";
|
||||
// eslint-disable-next-line import/no-internal-modules
|
||||
|
@ -51,7 +53,7 @@ interface TestSimpleTree {
|
|||
/**
|
||||
* InsertableTreeFieldFromImplicitField<TSchema>
|
||||
*/
|
||||
readonly root: InsertableTreeFieldFromImplicitField;
|
||||
readonly root: InsertableField<UnsafeUnknownSchema>;
|
||||
}
|
||||
|
||||
interface TestTree {
|
||||
|
@ -66,11 +68,11 @@ function testSimpleTree<TSchema extends ImplicitFieldSchema>(
|
|||
schema: TSchema,
|
||||
root: InsertableTreeFieldFromImplicitField<TSchema>,
|
||||
): TestSimpleTree {
|
||||
return { name, schema, root };
|
||||
return { name, schema, root: root as InsertableField<UnsafeUnknownSchema> };
|
||||
}
|
||||
|
||||
function convertSimpleTreeTest(data: TestSimpleTree): TestTree {
|
||||
const cursor = cursorFromInsertable(data.schema, data.root);
|
||||
const cursor = cursorFromInsertable<UnsafeUnknownSchema>(data.schema, data.root);
|
||||
return test(
|
||||
data.name,
|
||||
toStoredSchema(data.schema),
|
||||
|
|
|
@ -131,7 +131,6 @@ import {
|
|||
type ImplicitFieldSchema,
|
||||
type TreeViewConfiguration,
|
||||
SchemaFactory,
|
||||
type InsertableTreeFieldFromImplicitField,
|
||||
toStoredSchema,
|
||||
type TreeViewEvents,
|
||||
type TreeView,
|
||||
|
@ -146,7 +145,6 @@ import {
|
|||
} from "../util/index.js";
|
||||
import { isFluidHandle, toFluidHandleInternal } from "@fluidframework/runtime-utils/internal";
|
||||
import type { Client } from "@fluid-private/test-dds-utils";
|
||||
import { cursorFromInsertable } from "../simple-tree/index.js";
|
||||
import { JsonUnion, cursorToJsonObject, singleJsonCursor } from "./json/index.js";
|
||||
// eslint-disable-next-line import/no-internal-modules
|
||||
import type { TreeSimpleContent } from "./feature-libraries/flex-tree/utils.js";
|
||||
|
@ -1263,22 +1261,6 @@ export function validateUsageError(expectedErrorMsg: string | RegExp): (error: E
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cursor (in nodes mode) for the root node.
|
||||
*
|
||||
* @privateRemarks
|
||||
* Ideally this would work on any node, not just the root,
|
||||
* and the schema would come from the unhydrated node.
|
||||
* For now though, this is the only case that's needed, and we do have the data to make it work, so this is fine.
|
||||
*/
|
||||
export function cursorFromInsertableTreeField(
|
||||
schema: ImplicitFieldSchema,
|
||||
tree: InsertableTreeFieldFromImplicitField,
|
||||
nodeKeyManager: NodeKeyManager,
|
||||
): ITreeCursorSynchronous | undefined {
|
||||
return cursorFromInsertable(schema, tree, nodeKeyManager);
|
||||
}
|
||||
|
||||
function normalizeNewFieldContent(
|
||||
content: readonly ITreeCursorSynchronous[] | ITreeCursorSynchronous | undefined,
|
||||
): ITreeCursorSynchronous {
|
||||
|
|
|
@ -483,9 +483,9 @@ export type InsertableField<TSchema extends ImplicitFieldSchema | UnsafeUnknownS
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -1146,7 +1146,7 @@ export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | Unsa
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
|
@ -410,9 +410,9 @@ type _InlineTrick = 0;
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -936,7 +936,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
|
@ -510,9 +510,9 @@ type _InlineTrick = 0;
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -1321,7 +1321,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
|
@ -438,9 +438,9 @@ type _InlineTrick = 0;
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -960,7 +960,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
|
@ -410,9 +410,9 @@ type _InlineTrick = 0;
|
|||
|
||||
// @public
|
||||
type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = FlattenKeys<{
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
} & {
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property] & string> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property] & string>;
|
||||
readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
@ -920,7 +920,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
|
|||
}
|
||||
|
||||
// @public @sealed
|
||||
export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
export class TreeViewConfiguration<const TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> implements Required<ITreeViewConfiguration<TSchema>> {
|
||||
constructor(props: ITreeViewConfiguration<TSchema>);
|
||||
readonly enableSchemaValidation: boolean;
|
||||
readonly preventAmbiguity: boolean;
|
||||
|
|
Загрузка…
Ссылка в новой задаче