From f92e29d44612bd2eaa59fa7ce238b3c0597cf59c Mon Sep 17 00:00:00 2001 From: "Craig Macomber (Microsoft)" <42876482+CraigMacomber@users.noreply.github.com> Date: Wed, 28 Aug 2024 09:56:31 -0700 Subject: [PATCH] tree: Move Json domain to test code, and port to simple-tree schema (#22324) ## Description Move Json domain to test code, and port it to simple-tree schema. Replace Json schema in test/utils.ts with Json domain. Remove more schema aware typing logic. Make a few tests use more concise ways to build the needed test trees. --- packages/dds/tree/src/domains/index.ts | 10 - packages/dds/tree/src/domains/json/fence.json | 5 - .../tree/src/domains/json/jsonDomainSchema.ts | 52 ----- .../flex-tree/flexTreeTypes.ts | 5 +- .../dds/tree/src/feature-libraries/index.ts | 2 - .../feature-libraries/typed-schema/index.ts | 2 - .../typed-schema/schemaCollection.ts | 4 +- .../typed-schema/typedTreeSchema.ts | 60 ++---- packages/dds/tree/src/simple-tree/index.ts | 2 +- packages/dds/tree/src/simple-tree/mapNode.ts | 8 +- .../dds/tree/src/simple-tree/toFlexSchema.ts | 8 +- packages/dds/tree/src/test/cursorTestSuite.ts | 10 +- .../src/test/domains/json/jsonCursor.bench.ts | 4 +- .../src/test/domains/json/jsonCursor.spec.ts | 3 +- .../chunked-forest/basicChunk.spec.ts | 3 +- .../chunkEncodingEndToEnd.spec.ts | 39 ++-- .../chunked-forest/chunkTree.spec.ts | 9 +- .../chunked-forest/uniformChunk.spec.ts | 3 +- .../chunked-forest/uniformChunkTestData.ts | 37 ++-- .../defaultChangeFamily.spec.ts | 187 +++++++++--------- .../flex-map-tree/mapTreeNode.spec.ts | 2 - .../flex-tree/lazyField.spec.ts | 5 +- .../flex-tree/lazyNode.spec.ts | 4 +- .../flex-tree/unboxed.spec.ts | 3 +- .../modularChangeFamily.spec.ts | 7 +- .../feature-libraries/objectForest.spec.ts | 2 +- .../schema-index/codec.spec.ts | 8 +- .../schema-index/schemaSummarizer.spec.ts | 2 +- .../typedSchema/typedTreeSchema.spec.ts | 76 ++----- packages/dds/tree/src/test/forestTestSuite.ts | 48 ++--- .../tree/src/{domains => test}/json/index.ts | 2 +- .../src/{domains => test}/json/jsonCursor.ts | 36 ++-- .../tree/src/test/json/jsonDomainSchema.ts | 13 ++ .../dds/tree/src/test/scalableTestTrees.ts | 51 +---- .../dds/tree/src/test/sequenceRootUtils.ts | 9 +- .../edit-manager/editManager.bench.ts | 2 +- .../tree/src/test/shared-tree/editing.spec.ts | 28 ++- .../test/shared-tree/schematizeTree.spec.ts | 13 +- .../src/test/shared-tree/sharedTree.bench.ts | 2 +- .../src/test/shared-tree/sharedTree.spec.ts | 4 +- .../sharedTreeChangeEnricher.spec.ts | 2 +- .../tree/src/test/shared-tree/undo.spec.ts | 2 +- packages/dds/tree/src/test/testTrees.ts | 2 +- packages/dds/tree/src/test/utils.ts | 25 +-- 44 files changed, 283 insertions(+), 518 deletions(-) delete mode 100644 packages/dds/tree/src/domains/json/fence.json delete mode 100644 packages/dds/tree/src/domains/json/jsonDomainSchema.ts rename packages/dds/tree/src/{domains => test}/json/index.ts (69%) rename packages/dds/tree/src/{domains => test}/json/jsonCursor.ts (83%) create mode 100644 packages/dds/tree/src/test/json/jsonDomainSchema.ts diff --git a/packages/dds/tree/src/domains/index.ts b/packages/dds/tree/src/domains/index.ts index 26904f040479..724e5d991577 100644 --- a/packages/dds/tree/src/domains/index.ts +++ b/packages/dds/tree/src/domains/index.ts @@ -3,14 +3,4 @@ * Licensed under the MIT License. */ -export { - cursorToJsonObject, - jsonArray, - jsonObject, - jsonRoot, - jsonSchema, - singleJsonCursor, - fieldJsonCursor, -} from "./json/index.js"; - export { leaf } from "./leafDomain.js"; diff --git a/packages/dds/tree/src/domains/json/fence.json b/packages/dds/tree/src/domains/json/fence.json deleted file mode 100644 index 9a1630122d6c..000000000000 --- a/packages/dds/tree/src/domains/json/fence.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "tags": ["domains-json"], - "exports": ["index"], - "imports": ["util", "core", "feature-libraries", "domains"] -} diff --git a/packages/dds/tree/src/domains/json/jsonDomainSchema.ts b/packages/dds/tree/src/domains/json/jsonDomainSchema.ts deleted file mode 100644 index 61c14184f330..000000000000 --- a/packages/dds/tree/src/domains/json/jsonDomainSchema.ts +++ /dev/null @@ -1,52 +0,0 @@ -/*! - * Copyright (c) Microsoft Corporation and contributors. All rights reserved. - * Licensed under the MIT License. - */ - -// Adding this unused import makes the generated d.ts file produced by TypeScript stop breaking API-Extractor's rollup generation. -// Without this import, TypeScript generates inline `import("../..")` statements in the d.ts file, -// which API-Extractor leaves as is when generating the rollup, leaving them pointing at the wrong directory. -// API-Extractor issue: https://github.com/microsoft/rushstack/issues/4507 -// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports -import { EmptyKey, ValueSchema } from "../../core/index.js"; -import { - FieldKinds, - type FlexAllowedTypes, - FlexFieldSchema, - type FlexTreeNodeSchema, - SchemaBuilderInternal, -} from "../../feature-libraries/index.js"; -import type { requireAssignableTo } from "../../util/index.js"; -import { leaf } from "../leafDomain.js"; - -const builder = new SchemaBuilderInternal({ - scope: "com.fluidframework.json", - libraries: [leaf.library], -}); - -const jsonPrimitives = [...leaf.primitives, leaf.null] as const; - -/** - * Types allowed as roots of Json content. - */ -export const jsonRoot: FlexAllowedTypes = [ - (): FlexTreeNodeSchema => jsonObject, - (): FlexTreeNodeSchema => jsonArray, - ...jsonPrimitives, -]; - -{ - // Recursive objects don't get this type checking automatically, so confirm it - type _check = requireAssignableTo; -} - -export const jsonObject = builder.map( - "object", - FlexFieldSchema.create(FieldKinds.optional, jsonRoot), -); - -export const jsonArray = builder.object("array", { - [EmptyKey]: FlexFieldSchema.create(FieldKinds.sequence, jsonRoot), -}); - -export const jsonSchema = builder.intoLibrary(); diff --git a/packages/dds/tree/src/feature-libraries/flex-tree/flexTreeTypes.ts b/packages/dds/tree/src/feature-libraries/flex-tree/flexTreeTypes.ts index 77015961edc0..3460a4e3e4b2 100644 --- a/packages/dds/tree/src/feature-libraries/flex-tree/flexTreeTypes.ts +++ b/packages/dds/tree/src/feature-libraries/flex-tree/flexTreeTypes.ts @@ -276,9 +276,8 @@ export interface FlexTreeField extends FlexTreeEntity { * Additionally empty fields (those containing no nodes) are not distinguished from fields which do not exist. * This differs from JavaScript Maps which have a subtle distinction between storing undefined as a value in the map and deleting an entry from the map. */ -export interface FlexTreeMapNode - extends FlexTreeNode { - readonly schema: TSchema; +export interface FlexTreeMapNode extends FlexTreeNode { + readonly schema: FlexMapNodeSchema; } /** diff --git a/packages/dds/tree/src/feature-libraries/index.ts b/packages/dds/tree/src/feature-libraries/index.ts index 56d295e16d0a..f58020340d94 100644 --- a/packages/dds/tree/src/feature-libraries/index.ts +++ b/packages/dds/tree/src/feature-libraries/index.ts @@ -140,8 +140,6 @@ export { type FlexListToUnion, type ExtractItemType, isLazy, - type NormalizeObjectNodeFields, - type NormalizeField as NormalizeFieldSchema, type FlexObjectNodeFields, intoStoredSchema, intoStoredSchemaCollection, diff --git a/packages/dds/tree/src/feature-libraries/typed-schema/index.ts b/packages/dds/tree/src/feature-libraries/typed-schema/index.ts index e578ecb78379..dc01d826d991 100644 --- a/packages/dds/tree/src/feature-libraries/typed-schema/index.ts +++ b/packages/dds/tree/src/feature-libraries/typed-schema/index.ts @@ -22,8 +22,6 @@ export { schemaIsLeaf, schemaIsMap, schemaIsObjectNode, - type NormalizeObjectNodeFields, - type NormalizeField, intoStoredSchema, allowedTypesSchemaSet, intoStoredSchemaCollection, diff --git a/packages/dds/tree/src/feature-libraries/typed-schema/schemaCollection.ts b/packages/dds/tree/src/feature-libraries/typed-schema/schemaCollection.ts index 0e12c86d36c6..83d44772bc24 100644 --- a/packages/dds/tree/src/feature-libraries/typed-schema/schemaCollection.ts +++ b/packages/dds/tree/src/feature-libraries/typed-schema/schemaCollection.ts @@ -167,11 +167,11 @@ export function validateSchemaCollection( validateField( lintConfiguration, collection, - tree.info, + tree.info as FlexFieldSchema, () => `Map fields of "${identifier}" schema from library "${tree.builder.name}"`, errors, ); - if ((tree.info.kind.multiplicity as Multiplicity) === Multiplicity.Single) { + if ((tree.info as FlexFieldSchema).kind.multiplicity === Multiplicity.Single) { errors.push( `Map fields of "${identifier}" schema from library "${tree.builder.name}" has kind with multiplicity "Single". This is invalid since it requires all possible field keys to have a value under them.`, ); diff --git a/packages/dds/tree/src/feature-libraries/typed-schema/typedTreeSchema.ts b/packages/dds/tree/src/feature-libraries/typed-schema/typedTreeSchema.ts index 4547881f37fb..05ff492e3abe 100644 --- a/packages/dds/tree/src/feature-libraries/typed-schema/typedTreeSchema.ts +++ b/packages/dds/tree/src/feature-libraries/typed-schema/typedTreeSchema.ts @@ -41,12 +41,6 @@ export interface FlexObjectNodeFields { readonly [key: string]: FlexFieldSchema; } -/** - */ -export type NormalizeObjectNodeFields = { - readonly [Property in keyof T]: NormalizeField; -}; - /** * A placeholder to use in {@link https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-constraints | extends constraints} when using the real type breaks compilation of some recursive types due to {@link https://github.com/microsoft/TypeScript/issues/55758 | a design limitation of TypeScript}. * @@ -66,14 +60,11 @@ export type Unenforced<_DesiredExtendsConstraint> = unknown; * This can not be enforced using TypeScript since doing so breaks recursive type support. * See note on SchemaBuilder.fieldRecursive. */ -export abstract class TreeNodeSchemaBase< - const out Name extends string = string, - const out Specification = unknown, -> { +export abstract class TreeNodeSchemaBase { protected _typeCheck!: MakeNominal; protected constructor( public readonly builder: Named, - public readonly name: TreeNodeSchemaIdentifier, + public readonly name: TreeNodeSchemaIdentifier, public readonly info: Specification, public readonly stored: TreeNodeStoredSchema, ) {} @@ -82,23 +73,17 @@ export abstract class TreeNodeSchemaBase< /** */ -export class FlexMapNodeSchema< - const out Name extends string = string, - const out Specification extends Unenforced = FlexMapFieldSchema, -> extends TreeNodeSchemaBase { +export class FlexMapNodeSchema extends TreeNodeSchemaBase { public get mapFields(): FlexMapFieldSchema { return this.info as FlexMapFieldSchema; } protected _typeCheck2?: MakeNominal; - public static create< - const Name extends string, - const Specification extends FlexMapFieldSchema, - >( + public static create( builder: Named, name: TreeNodeSchemaIdentifier, - specification: Specification, - ): FlexMapNodeSchema { + specification: FlexMapFieldSchema, + ): FlexMapNodeSchema { return new FlexMapNodeSchema( builder, name, @@ -114,7 +99,7 @@ export class FlexMapNodeSchema< /** */ -export class LeafNodeSchema extends TreeNodeSchemaBase { +export class LeafNodeSchema extends TreeNodeSchemaBase { public get leafValue(): ValueSchema { return this.info; } @@ -140,7 +125,7 @@ export class LeafNodeSchema extends TreeNodeSchemaBase { /** */ -export class FlexObjectNodeSchema extends TreeNodeSchemaBase { +export class FlexObjectNodeSchema extends TreeNodeSchemaBase { protected _typeCheck2?: MakeNominal; public readonly identifierFieldKeys: readonly FieldKey[] = []; @@ -149,13 +134,9 @@ export class FlexObjectNodeSchema extends TreeNodeSchemaBase = - normalizeStructFields(specification); - const objectNodeFields: ObjectToMap< - NormalizeObjectNodeFields, - FieldKey, - FlexFieldSchema - > = objectToMapTyped(objectNodeFieldsObject); + const objectNodeFieldsObject = normalizeStructFields(specification); + const objectNodeFields: ObjectToMap = + objectToMapTyped(objectNodeFieldsObject); return new FlexObjectNodeSchema( builder, name, @@ -169,7 +150,7 @@ export class FlexObjectNodeSchema extends TreeNodeSchemaBase, name: TreeNodeSchemaIdentifier, info: FlexObjectNodeFields, - public readonly objectNodeFieldsObject: NormalizeObjectNodeFields, + public readonly objectNodeFieldsObject: FlexObjectNodeFields, // Allows reading fields through the normal map. // Stricter typing caused Specification to no longer be covariant, so has been removed. public readonly objectNodeFields: ReadonlyMap, @@ -199,16 +180,9 @@ export class FlexObjectNodeSchema extends TreeNodeSchemaBase = T extends FlexFieldSchema - ? T - : FlexFieldSchema; - function normalizeStructFields( fields: T, -): NormalizeObjectNodeFields { +): FlexObjectNodeFields { const out: Record = {}; // eslint-disable-next-line no-restricted-syntax for (const key in fields) { @@ -217,16 +191,16 @@ function normalizeStructFields( out[key] = normalizeField(element); } } - return out as NormalizeObjectNodeFields; + return out; } -function normalizeField(t: T): NormalizeField { +function normalizeField(t: FlexFieldSchema | undefined): FlexFieldSchema { if (t === undefined) { - return FlexFieldSchema.empty as unknown as NormalizeField; + return FlexFieldSchema.empty; } assert(t instanceof FlexFieldSchema, 0x6ae /* invalid TreeFieldSchema */); - return t as NormalizeField; + return t; } /** diff --git a/packages/dds/tree/src/simple-tree/index.ts b/packages/dds/tree/src/simple-tree/index.ts index 30c3187c6fc0..2799af132d21 100644 --- a/packages/dds/tree/src/simple-tree/index.ts +++ b/packages/dds/tree/src/simple-tree/index.ts @@ -122,4 +122,4 @@ export { } from "./jsonSchema.js"; export { getJsonSchema } from "./getJsonSchema.js"; export { getSimpleSchema } from "./getSimpleSchema.js"; -export { toStoredSchema, getStoredSchema } from "./toFlexSchema.js"; +export { toStoredSchema, getStoredSchema, getFlexSchema } from "./toFlexSchema.js"; diff --git a/packages/dds/tree/src/simple-tree/mapNode.ts b/packages/dds/tree/src/simple-tree/mapNode.ts index c5ba7b25c727..e9b4f954fc84 100644 --- a/packages/dds/tree/src/simple-tree/mapNode.ts +++ b/packages/dds/tree/src/simple-tree/mapNode.ts @@ -4,8 +4,6 @@ */ import { - type FieldKinds, - type FlexFieldSchema, type FlexMapNodeSchema, type FlexTreeMapNode, type FlexTreeNode, @@ -145,10 +143,8 @@ abstract class CustomMapNodeBase extends T return this.entries(); } - private get innerNode(): InnerNode & - FlexTreeMapNode>> { - return getOrCreateInnerNode(this) as InnerNode & - FlexTreeMapNode>>; + private get innerNode(): InnerNode & FlexTreeMapNode { + return getOrCreateInnerNode(this) as InnerNode & FlexTreeMapNode; } private editor(key: string): OptionalFieldEditBuilder { diff --git a/packages/dds/tree/src/simple-tree/toFlexSchema.ts b/packages/dds/tree/src/simple-tree/toFlexSchema.ts index 14e1e790bdb4..04bdca9df57d 100644 --- a/packages/dds/tree/src/simple-tree/toFlexSchema.ts +++ b/packages/dds/tree/src/simple-tree/toFlexSchema.ts @@ -199,7 +199,13 @@ export function convertNodeSchema( ); // Lookup of cached schema is done here instead of before since walking the schema recursively to populate schemaMap is still required. const cached = cachedFlexSchemaFromClassSchema(schema); - out = cached ?? FlexMapNodeSchema.create(builder, brand(schema.identifier), field); + out = + cached ?? + FlexMapNodeSchema.create( + builder, + brand(schema.identifier), + field, + ); break; } case NodeKind.Array: { diff --git a/packages/dds/tree/src/test/cursorTestSuite.ts b/packages/dds/tree/src/test/cursorTestSuite.ts index 581773f84c04..26ba74e0776f 100644 --- a/packages/dds/tree/src/test/cursorTestSuite.ts +++ b/packages/dds/tree/src/test/cursorTestSuite.ts @@ -27,15 +27,9 @@ import { prefixPath, } from "../feature-libraries/index.js"; import { brand } from "../util/index.js"; - -import { - expectEqualFieldPaths, - expectEqualPaths, - IdentifierSchema, - JsonArray, - JsonObject, -} from "./utils.js"; +import { expectEqualFieldPaths, expectEqualPaths, IdentifierSchema } from "./utils.js"; import { SchemaFactory } from "../simple-tree/index.js"; +import { JsonArray, JsonObject } from "./json/index.js"; const sf = new SchemaFactory("Cursor Test Suite"); diff --git a/packages/dds/tree/src/test/domains/json/jsonCursor.bench.ts b/packages/dds/tree/src/test/domains/json/jsonCursor.bench.ts index 031dff146037..f340857ff1a4 100644 --- a/packages/dds/tree/src/test/domains/json/jsonCursor.bench.ts +++ b/packages/dds/tree/src/test/domains/json/jsonCursor.bench.ts @@ -16,7 +16,6 @@ import { initializeForest, moveToDetachedField, } from "../../../core/index.js"; -import { cursorToJsonObject, singleJsonCursor } from "../../../domains/index.js"; import { basicChunkTree, defaultChunkPolicy, @@ -34,7 +33,7 @@ import { } from "../../../feature-libraries/index.js"; import { brand, type JsonCompatible } from "../../../util/index.js"; -import { JsonUnion, testIdCompressor, testRevisionTagCodec } from "../../utils.js"; +import { testIdCompressor, testRevisionTagCodec } from "../../utils.js"; import { averageValues, sum, sumMap } from "./benchmarks.js"; import { Canada, generateCanada } from "./canada.js"; import { CitmCatalog, generateCitmJson } from "./citm.js"; @@ -42,6 +41,7 @@ import { clone } from "./jsObjectUtil.js"; import { generateTwitterJsonByByteSize } from "./twitter.js"; // eslint-disable-next-line import/no-internal-modules import { toStoredSchema } from "../../../simple-tree/toFlexSchema.js"; +import { JsonUnion, cursorToJsonObject, singleJsonCursor } from "../../json/index.js"; // Shared tree keys that map to the type used by the Twitter type/dataset export const TwitterKey = { diff --git a/packages/dds/tree/src/test/domains/json/jsonCursor.spec.ts b/packages/dds/tree/src/test/domains/json/jsonCursor.spec.ts index 5c53238cdbdc..5e0171067a9a 100644 --- a/packages/dds/tree/src/test/domains/json/jsonCursor.spec.ts +++ b/packages/dds/tree/src/test/domains/json/jsonCursor.spec.ts @@ -3,8 +3,7 @@ * Licensed under the MIT License. */ -// eslint-disable-next-line import/no-internal-modules -import { cursorToJsonObject, singleJsonCursor } from "../../../domains/json/index.js"; +import { cursorToJsonObject, singleJsonCursor } from "../../json/index.js"; import type { JsonCompatible } from "../../../util/index.js"; import { testSpecializedCursor } from "../../cursorTestSuite.js"; diff --git a/packages/dds/tree/src/test/feature-libraries/chunked-forest/basicChunk.spec.ts b/packages/dds/tree/src/test/feature-libraries/chunked-forest/basicChunk.spec.ts index b800fed6e4a8..3d59eedc4c41 100644 --- a/packages/dds/tree/src/test/feature-libraries/chunked-forest/basicChunk.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/chunked-forest/basicChunk.spec.ts @@ -40,10 +40,9 @@ import { testGeneralPurposeTreeCursor, testSpecializedFieldCursor, } from "../../cursorTestSuite.js"; - import { numberSequenceField, validateChunkCursor } from "./fieldCursorTestUtilities.js"; import { emptyShape, testData } from "./uniformChunkTestData.js"; -import { JsonObject } from "../../utils.js"; +import { JsonObject } from "../../json/index.js"; describe("basic chunk", () => { it("calling chunkTree on existing chunk adds a reference", () => { diff --git a/packages/dds/tree/src/test/feature-libraries/chunked-forest/chunkEncodingEndToEnd.spec.ts b/packages/dds/tree/src/test/feature-libraries/chunked-forest/chunkEncodingEndToEnd.spec.ts index 99c11522530d..4feeffb18a51 100644 --- a/packages/dds/tree/src/test/feature-libraries/chunked-forest/chunkEncodingEndToEnd.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/chunked-forest/chunkEncodingEndToEnd.spec.ts @@ -9,8 +9,8 @@ import { createIdCompressor } from "@fluidframework/id-compressor/internal"; import { type ChangesetLocalId, - type IEditableForest, RevisionTagCodec, + rootFieldKey, TreeStoredSchemaRepository, } from "../../../core/index.js"; import { leaf } from "../../../domains/index.js"; @@ -37,8 +37,6 @@ import { buildChunkedForest, defaultSchemaPolicy, fieldKindConfigurations, - getTreeContext, - intoStoredSchema, makeFieldBatchCodec, makeModularChangeCodecFamily, MockNodeKeyManager, @@ -52,9 +50,7 @@ import { MockTreeCheckout, checkoutWithContent, cursorFromInsertableTreeField, - flexTreeViewWithContent, forestWithContent, - numberSequenceRootSchema, testIdCompressor, } from "../../utils.js"; import { SchemaFactory } from "../../../simple-tree/index.js"; @@ -65,6 +61,7 @@ import { SummaryType } from "@fluidframework/driver-definitions"; import type { Format } from "../../../feature-libraries/forest-summary/format.js"; // eslint-disable-next-line import/no-internal-modules import type { EncodedFieldBatch } from "../../../feature-libraries/chunked-forest/index.js"; +import { jsonSequenceRootSchema } from "../../sequenceRootUtils.js"; const options = { jsonValidator: typeboxValidator, @@ -81,7 +78,7 @@ const context = { encodeType: options.summaryEncodeType, idCompressor, originatorId: idCompressor.localSessionId, - schema: { schema: intoStoredSchema(numberSequenceRootSchema), policy: defaultSchemaPolicy }, + schema: { schema: jsonSequenceRootSchema, policy: defaultSchemaPolicy }, }; const schemaFactory = new SchemaFactory("com.example"); @@ -116,9 +113,7 @@ function getIdentifierEncodingContext(id: string) { describe("End to end chunked encoding", () => { it(`insert ops shares reference with the original chunk.`, () => { - const treeSchema = new TreeStoredSchemaRepository( - intoStoredSchema(numberSequenceRootSchema), - ); + const treeSchema = new TreeStoredSchemaRepository(jsonSequenceRootSchema); const chunker = new Chunker( treeSchema, defaultSchemaPolicy, @@ -145,17 +140,9 @@ describe("End to end chunked encoding", () => { ); const dummyEditor = new DefaultEditBuilder(new DefaultChangeFamily(codec), changeReceiver); const checkout = new MockTreeCheckout(forest, dummyEditor as unknown as ISharedTreeEditor); - const flexTree = getTreeContext( - numberSequenceRootSchema, - // Note: deliberately passing an editor that doesn't have the property for schema edition; test doesn't need it - checkout, - new MockNodeKeyManager(), - ); - - const root = flexTree.root; - assert(root.isExactly(numberSequenceRootSchema.rootFieldSchema)); - checkout.editor.sequenceField(root.getFieldPath()).insert(0, chunk.cursor()); - + checkout.editor + .sequenceField({ field: rootFieldKey, parent: undefined }) + .insert(0, chunk.cursor()); // Check that inserted change contains chunk which is reference equal to the original chunk. const insertedChange = changeLog[0]; assert(insertedChange.builds !== undefined); @@ -170,17 +157,17 @@ describe("End to end chunked encoding", () => { const numberShape = new TreeShape(leaf.number.name, true, []); const chunk = new UniformChunk(numberShape.withTopLevelLength(4), [1, 2, 3, 4]); assert(!chunk.isShared()); - const flexTree = flexTreeViewWithContent({ - schema: numberSequenceRootSchema, + const checkout = checkoutWithContent({ + schema: jsonSequenceRootSchema, initialTree: [], }); - flexTree.checkout.editor - .sequenceField(flexTree.flexTree.getFieldPath()) + checkout.editor + .sequenceField({ field: rootFieldKey, parent: undefined }) .insert(0, chunk.cursor()); const forestSummarizer = new ForestSummarizer( - flexTree.context.checkout.forest as IEditableForest, + checkout.forest, revisionTagCodec, fieldBatchCodec, context, @@ -208,7 +195,7 @@ describe("End to end chunked encoding", () => { assert(!chunk.isShared()); const forest = forestWithContent({ - schema: numberSequenceRootSchema, + schema: jsonSequenceRootSchema, initialTree: chunk.cursor(), }); diff --git a/packages/dds/tree/src/test/feature-libraries/chunked-forest/chunkTree.spec.ts b/packages/dds/tree/src/test/feature-libraries/chunked-forest/chunkTree.spec.ts index a4dbc3be92f6..075599d23f8d 100644 --- a/packages/dds/tree/src/test/feature-libraries/chunked-forest/chunkTree.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/chunked-forest/chunkTree.spec.ts @@ -11,7 +11,7 @@ import { type Value, mapCursorField, } from "../../../core/index.js"; -import { jsonObject, leaf } from "../../../domains/index.js"; +import { leaf } from "../../../domains/index.js"; // eslint-disable-next-line import/no-internal-modules import { BasicChunk } from "../../../feature-libraries/chunked-forest/basicChunk.js"; // eslint-disable-next-line import/no-internal-modules @@ -49,6 +49,7 @@ import { } from "./fieldCursorTestUtilities.js"; import { polygonTree, testData } from "./uniformChunkTestData.js"; import { SchemaFactory, toStoredSchema } from "../../../simple-tree/index.js"; +import { fieldJsonCursor } from "../../json/index.js"; const builder = new SchemaFactory("chunkTree"); const empty = builder.object("empty", {}); @@ -114,11 +115,7 @@ describe("chunkTree", () => { }); it("stops if type changes", () => { - const cursor = cursorForJsonableTreeField([ - { type: leaf.null.name }, - { type: leaf.null.name }, - { type: jsonObject.name }, - ]); + const cursor = fieldJsonCursor([null, null, {}]); cursor.firstNode(); const nullShape = new TreeShape(leaf.null.name, false, []); { diff --git a/packages/dds/tree/src/test/feature-libraries/chunked-forest/uniformChunk.spec.ts b/packages/dds/tree/src/test/feature-libraries/chunked-forest/uniformChunk.spec.ts index d8919365ee90..5b02c3eda845 100644 --- a/packages/dds/tree/src/test/feature-libraries/chunked-forest/uniformChunk.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/chunked-forest/uniformChunk.spec.ts @@ -8,7 +8,7 @@ import { strict as assert } from "assert"; import { BenchmarkType, benchmark } from "@fluid-tools/benchmark"; import { EmptyKey, type ITreeCursorSynchronous } from "../../../core/index.js"; -import { cursorToJsonObject, singleJsonCursor } from "../../../domains/index.js"; +import { cursorToJsonObject, singleJsonCursor, JsonObject } from "../../json/index.js"; import { type ChunkShape, TreeShape, @@ -27,7 +27,6 @@ import { testSpecializedFieldCursor } from "../../cursorTestSuite.js"; import { sum } from "../../domains/json/benchmarks.js"; import { emptyShape, polygonTree, testData, xField, yField } from "./uniformChunkTestData.js"; -import { JsonObject } from "../../utils.js"; import { brand } from "../../../util/index.js"; // Validate a few aspects of shapes that are easier to verify here than via checking the cursor. diff --git a/packages/dds/tree/src/test/feature-libraries/chunked-forest/uniformChunkTestData.ts b/packages/dds/tree/src/test/feature-libraries/chunked-forest/uniformChunkTestData.ts index 4642514e680e..7ffa9720ab46 100644 --- a/packages/dds/tree/src/test/feature-libraries/chunked-forest/uniformChunkTestData.ts +++ b/packages/dds/tree/src/test/feature-libraries/chunked-forest/uniformChunkTestData.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. */ -import { EmptyKey, type FieldKey } from "../../../core/index.js"; -import { jsonArray, jsonObject, leaf } from "../../../domains/index.js"; +import { EmptyKey, type FieldKey, type JsonableTree } from "../../../core/index.js"; +import { leaf } from "../../../domains/index.js"; // eslint-disable-next-line import/no-internal-modules import { dummyRoot } from "../../../feature-libraries/chunked-forest/index.js"; import { @@ -14,6 +14,7 @@ import { } from "../../../feature-libraries/chunked-forest/uniformChunk.js"; import { brand, makeArray } from "../../../util/index.js"; import { type TestField, EmptyObject } from "../../cursorTestSuite.js"; +import { JsonArray, JsonObject } from "../../json/index.js"; export const emptyShape = new TreeShape(brand(EmptyObject.identifier), false, []); @@ -21,14 +22,16 @@ export const xField: FieldKey = brand("x"); export const yField: FieldKey = brand("y"); const numberShape = new TreeShape(leaf.number.name, true, []); -const withChildShape = new TreeShape(jsonObject.name, false, [[xField, numberShape, 1]]); -const pointShape = new TreeShape(jsonObject.name, false, [ +const withChildShape = new TreeShape(brand(JsonObject.identifier), false, [ + [xField, numberShape, 1], +]); +const pointShape = new TreeShape(brand(JsonObject.identifier), false, [ [xField, numberShape, 1], [yField, numberShape, 1], ]); const sides = 100; -const polygon = new TreeShape(jsonArray.name, false, [ +const polygon = new TreeShape(brand(JsonArray.identifier), false, [ [EmptyKey, pointShape, sides], ]).withTopLevelLength(1); @@ -40,20 +43,24 @@ export const polygonTree = { makeArray(sides * 2, (index) => index), ), reference: { - type: jsonArray.name, + type: brand(JsonArray.identifier), fields: { [EmptyKey]: makeArray(sides, (index) => ({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { x: [{ type: leaf.number.name, value: index * 2 }], y: [{ type: leaf.number.name, value: index * 2 + 1 }], }, })), }, - }, + } satisfies JsonableTree, } as const; -const testTrees = [ +const testTrees: { + name: string; + dataFactory: () => UniformChunk; + reference: JsonableTree[]; +}[] = [ { name: "number", dataFactory: () => new UniformChunk(numberShape.withTopLevelLength(1), [5]), @@ -72,14 +79,14 @@ const testTrees = [ name: "child sequence", dataFactory: () => new UniformChunk( - new TreeShape(jsonArray.name, false, [[EmptyKey, numberShape, 3]]).withTopLevelLength( - 1, - ), + new TreeShape(brand(JsonArray.identifier), false, [ + [EmptyKey, numberShape, 3], + ]).withTopLevelLength(1), [1, 2, 3], ), reference: [ { - type: jsonArray.name, + type: brand(JsonArray.identifier), fields: { [EmptyKey]: [ { type: leaf.number.name, value: 1 }, @@ -95,7 +102,7 @@ const testTrees = [ dataFactory: () => new UniformChunk(withChildShape.withTopLevelLength(1), [1]), reference: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { x: [{ type: leaf.number.name, value: 1 }], }, @@ -107,7 +114,7 @@ const testTrees = [ dataFactory: () => new UniformChunk(pointShape.withTopLevelLength(1), [1, 2]), reference: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { x: [{ type: leaf.number.name, value: 1 }], y: [{ type: leaf.number.name, value: 2 }], diff --git a/packages/dds/tree/src/test/feature-libraries/default-field-kinds/defaultChangeFamily.spec.ts b/packages/dds/tree/src/test/feature-libraries/default-field-kinds/defaultChangeFamily.spec.ts index 1107ad7ab5e3..0adf0c3bdc13 100644 --- a/packages/dds/tree/src/test/feature-libraries/default-field-kinds/defaultChangeFamily.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/default-field-kinds/defaultChangeFamily.spec.ts @@ -19,7 +19,7 @@ import { moveToDetachedField, rootFieldKey, } from "../../../core/index.js"; -import { jsonObject, leaf } from "../../../domains/index.js"; +import { leaf } from "../../../domains/index.js"; import { DefaultChangeFamily, type DefaultChangeset, @@ -37,6 +37,7 @@ import { testIdCompressor, testRevisionTagCodec, } from "../../utils.js"; +import { JsonObject } from "../../json/index.js"; const defaultChangeFamily = new DefaultChangeFamily(failCodecFamily); const family = defaultChangeFamily; @@ -164,7 +165,7 @@ describe("DefaultEditBuilder", () => { it("Produces one delta for each editing call made to it", () => { const { builder, deltas, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, @@ -177,7 +178,7 @@ describe("DefaultEditBuilder", () => { assert.equal(deltas.length, 1); fooEditor.insert(0, cursorForJsonableTreeNode({ type: leaf.number.name, value: 42 })); expectForest(forest, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 42 }], }, @@ -190,7 +191,9 @@ describe("DefaultEditBuilder", () => { describe("Value Field Edits", () => { it("Can overwrite a populated root field", () => { - const { builder, forest } = initializeEditableForest({ type: jsonObject.name }); + const { builder, forest } = initializeEditableForest({ + type: brand(JsonObject.identifier), + }); builder .valueField({ parent: undefined, field: rootKey }) .set(cursorForJsonableTreeNode(nodeX)); @@ -199,13 +202,13 @@ describe("DefaultEditBuilder", () => { it("Can overwrite a populated child field", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, @@ -216,14 +219,14 @@ describe("DefaultEditBuilder", () => { builder .valueField({ parent: root_foo2, field: fooKey }) .set(cursorForJsonableTreeNode(nodeX)); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [nodeX], }, @@ -237,7 +240,9 @@ describe("DefaultEditBuilder", () => { describe("Optional Field Edits", () => { it("Can overwrite a populated root field", () => { - const { builder, forest } = initializeEditableForest({ type: jsonObject.name }); + const { builder, forest } = initializeEditableForest({ + type: brand(JsonObject.identifier), + }); builder .optionalField({ parent: undefined, field: rootKey }) .set(cursorForJsonableTreeNode(nodeX), false); @@ -246,13 +251,13 @@ describe("DefaultEditBuilder", () => { it("Can overwrite a populated child field", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, @@ -263,14 +268,14 @@ describe("DefaultEditBuilder", () => { builder .optionalField({ parent: root_foo2, field: fooKey }) .set(cursorForJsonableTreeNode(nodeX), false); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [nodeX], }, @@ -291,25 +296,25 @@ describe("DefaultEditBuilder", () => { it("Can set an empty child field", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, - { type: jsonObject.name }, + { type: brand(JsonObject.identifier) }, ], }, }); builder .optionalField({ parent: root_foo2, field: fooKey }) .set(cursorForJsonableTreeNode(nodeX), true); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, - { type: jsonObject.name, fields: { foo: [nodeX] } }, + { type: brand(JsonObject.identifier), fields: { foo: [nodeX] } }, ], }, }; @@ -328,13 +333,13 @@ describe("DefaultEditBuilder", () => { it("Can insert a child node", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -351,14 +356,14 @@ describe("DefaultEditBuilder", () => { builder .sequenceField({ parent: root_foo2, field: fooKey }) .insert(5, cursorForJsonableTreeNode(nodeX)); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -384,13 +389,13 @@ describe("DefaultEditBuilder", () => { it("Can remove child nodes", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -407,14 +412,14 @@ describe("DefaultEditBuilder", () => { }, }); builder.sequenceField({ parent: root_foo2, field: fooKey }).remove(5, 2); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, { type: leaf.number.name, value: 1 }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -433,7 +438,7 @@ describe("DefaultEditBuilder", () => { it("Can move nodes to the right within a field", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -445,8 +450,8 @@ describe("DefaultEditBuilder", () => { }); builder.move({ parent: root, field: fooKey }, 0, 3, { parent: root, field: fooKey }, 4); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 3 }, @@ -461,7 +466,7 @@ describe("DefaultEditBuilder", () => { it("Can move nodes to the left within a field", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -473,8 +478,8 @@ describe("DefaultEditBuilder", () => { }); builder.move({ parent: root, field: fooKey }, 1, 3, { parent: root, field: fooKey }, 0); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 1 }, @@ -489,7 +494,7 @@ describe("DefaultEditBuilder", () => { it("Can move nodes in their own midst", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -501,8 +506,8 @@ describe("DefaultEditBuilder", () => { }); builder.move({ parent: root, field: fooKey }, 1, 2, { parent: root, field: fooKey }, 2); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -517,7 +522,7 @@ describe("DefaultEditBuilder", () => { it("Can move nodes across fields of the same parent", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -530,8 +535,8 @@ describe("DefaultEditBuilder", () => { }); builder.move({ parent: root, field: fooKey }, 1, 3, { parent: root, field: barKey }, 1); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], bar: [ @@ -547,11 +552,11 @@ describe("DefaultEditBuilder", () => { it("Can move nodes to the right across subtrees of the same field", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -562,7 +567,7 @@ describe("DefaultEditBuilder", () => { }, }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, @@ -578,18 +583,18 @@ describe("DefaultEditBuilder", () => { 1, ); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -607,17 +612,17 @@ describe("DefaultEditBuilder", () => { it("Can move nodes to the left across subtrees of the same field", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -638,12 +643,12 @@ describe("DefaultEditBuilder", () => { 1, ); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -654,7 +659,7 @@ describe("DefaultEditBuilder", () => { }, }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, @@ -667,11 +672,11 @@ describe("DefaultEditBuilder", () => { it("Can move nodes across subtrees of different fields", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -684,7 +689,7 @@ describe("DefaultEditBuilder", () => { ], bar: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { bar: [{ type: leaf.number.name, value: 0 }], }, @@ -700,12 +705,12 @@ describe("DefaultEditBuilder", () => { 1, ); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, @@ -713,7 +718,7 @@ describe("DefaultEditBuilder", () => { ], bar: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { bar: [ { type: leaf.number.name, value: 0 }, @@ -731,11 +736,11 @@ describe("DefaultEditBuilder", () => { it("Can move nodes before an ancestor of the moved node", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -756,15 +761,15 @@ describe("DefaultEditBuilder", () => { 0, ); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 1 }, { type: leaf.number.name, value: 2 }, { type: leaf.number.name, value: 3 }, { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, @@ -777,11 +782,11 @@ describe("DefaultEditBuilder", () => { it("Can move nodes after an ancestor of the moved node", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -802,12 +807,12 @@ describe("DefaultEditBuilder", () => { 1, ); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, @@ -822,12 +827,12 @@ describe("DefaultEditBuilder", () => { }); it("Errors when attempting to move a node under itself", () => { - const statingState = { - type: jsonObject.name, + const statingState: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), }, ], }, @@ -848,15 +853,15 @@ describe("DefaultEditBuilder", () => { it("Can move nodes across deep subtrees of different fields", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 0 }, @@ -872,7 +877,7 @@ describe("DefaultEditBuilder", () => { ], bar: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { bar: [ { @@ -895,16 +900,16 @@ describe("DefaultEditBuilder", () => { 1, ); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [{ type: leaf.number.name, value: 0 }], }, @@ -915,7 +920,7 @@ describe("DefaultEditBuilder", () => { ], bar: [ { - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { bar: [ { @@ -940,7 +945,7 @@ describe("DefaultEditBuilder", () => { it("Can move all nodes into another field", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [ { type: leaf.number.name, value: 1 }, @@ -952,8 +957,8 @@ describe("DefaultEditBuilder", () => { }); builder.move({ parent: root, field: fooKey }, 0, 3, { parent: root, field: barKey }, 1); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { bar: [ { type: leaf.number.name, value: 0 }, @@ -968,15 +973,15 @@ describe("DefaultEditBuilder", () => { it("Moving 0 items does nothing.", () => { const { builder, forest } = initializeEditableForest({ - type: jsonObject.name, + type: brand(JsonObject.identifier), fields: { foo: [], }, }); builder.move({ parent: root, field: fooKey }, 0, 0, { parent: root, field: fooKey }, 0); const treeView = toJsonableTreeFromForest(forest); - const expected = { - type: jsonObject.name, + const expected: JsonableTree = { + type: brand(JsonObject.identifier), fields: { foo: [], }, diff --git a/packages/dds/tree/src/test/feature-libraries/flex-map-tree/mapTreeNode.spec.ts b/packages/dds/tree/src/test/feature-libraries/flex-map-tree/mapTreeNode.spec.ts index f7b24c3ca82b..529f6804b2ba 100644 --- a/packages/dds/tree/src/test/feature-libraries/flex-map-tree/mapTreeNode.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/flex-map-tree/mapTreeNode.spec.ts @@ -125,8 +125,6 @@ describe("MapTreeNodes", () => { assert.equal(arrayNode.getBoxed(EmptyKey).length, 1); const field = arrayNode.getBoxed(EmptyKey); - assert(field.isExactly(arrayNodeSchema.info[EmptyKey])); - assert(field.is(arrayNodeSchema.info[EmptyKey].kind)); assert.equal(arrayNode.tryGetField(brand("unknown key")), undefined); assert.equal(arrayNode.getBoxed("unknown key").length, 0); assert(field.is(FieldKinds.sequence)); diff --git a/packages/dds/tree/src/test/feature-libraries/flex-tree/lazyField.spec.ts b/packages/dds/tree/src/test/feature-libraries/flex-tree/lazyField.spec.ts index 31caa2ec92b8..940a03fca11c 100644 --- a/packages/dds/tree/src/test/feature-libraries/flex-tree/lazyField.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/flex-tree/lazyField.spec.ts @@ -15,7 +15,7 @@ import { type UpPath, rootFieldKey, } from "../../../core/index.js"; -import { leaf, leaf as leafDomain, singleJsonCursor } from "../../../domains/index.js"; +import { leaf, leaf as leafDomain } from "../../../domains/index.js"; import { isFreedSymbol } from "../../../feature-libraries/flex-tree/lazyEntity.js"; import { LazyField, @@ -33,7 +33,7 @@ import { type FlexTreeSchema, } from "../../../feature-libraries/index.js"; import { brand, disposeSymbol } from "../../../util/index.js"; -import { flexTreeViewWithContent, forestWithContent, JsonObject } from "../../utils.js"; +import { flexTreeViewWithContent, forestWithContent } from "../../utils.js"; import { getReadonlyContext, @@ -47,6 +47,7 @@ import { toFlexSchema, } from "../../../simple-tree/index.js"; import { getFlexSchema } from "../../../simple-tree/toFlexSchema.js"; +import { JsonObject, singleJsonCursor } from "../../json/index.js"; const detachedField: FieldKey = brand("detached"); const detachedFieldAnchor: FieldAnchor = { parent: undefined, fieldKey: detachedField }; diff --git a/packages/dds/tree/src/test/feature-libraries/flex-tree/lazyNode.spec.ts b/packages/dds/tree/src/test/feature-libraries/flex-tree/lazyNode.spec.ts index 6c6b03d7cb09..b2b7e6e7a2ee 100644 --- a/packages/dds/tree/src/test/feature-libraries/flex-tree/lazyNode.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/flex-tree/lazyNode.spec.ts @@ -18,7 +18,7 @@ import { TreeNavigationResult, rootFieldKey, } from "../../../core/index.js"; -import { leaf as leafDomain, singleJsonCursor } from "../../../domains/index.js"; +import { leaf as leafDomain } from "../../../domains/index.js"; import type { Context } from "../../../feature-libraries/flex-tree/context.js"; import { LazyTreeNode } from "../../../feature-libraries/flex-tree/lazyNode.js"; import type { @@ -37,7 +37,7 @@ import { toFlexSchema, } from "../../../simple-tree/index.js"; import { getFlexSchema } from "../../../simple-tree/toFlexSchema.js"; -import { JsonArray, JsonObject } from "../../utils.js"; +import { JsonArray, JsonObject, singleJsonCursor } from "../../json/index.js"; import { stringSchema } from "../../../simple-tree/leafNodeSchema.js"; const rootFieldAnchor: FieldAnchor = { parent: undefined, fieldKey: rootFieldKey }; diff --git a/packages/dds/tree/src/test/feature-libraries/flex-tree/unboxed.spec.ts b/packages/dds/tree/src/test/feature-libraries/flex-tree/unboxed.spec.ts index 02fce729e688..ca70339d8474 100644 --- a/packages/dds/tree/src/test/feature-libraries/flex-tree/unboxed.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/flex-tree/unboxed.spec.ts @@ -13,7 +13,7 @@ import { TreeNavigationResult, rootFieldKey, } from "../../../core/index.js"; -import { leaf, leaf as leafDomain, singleJsonCursor } from "../../../domains/index.js"; +import { leaf, leaf as leafDomain } from "../../../domains/index.js"; import type { Context } from "../../../feature-libraries/flex-tree/context.js"; import { unboxedTree, unboxedUnion } from "../../../feature-libraries/flex-tree/unboxed.js"; import type { @@ -26,6 +26,7 @@ import type { TreeContent } from "../../../shared-tree/index.js"; import { contextWithContentReadonly } from "./utils.js"; import { SchemaFactory, toFlexSchema } from "../../../simple-tree/index.js"; import { stringSchema } from "../../../simple-tree/leafNodeSchema.js"; +import { singleJsonCursor } from "../../json/index.js"; const rootFieldAnchor: FieldAnchor = { parent: undefined, fieldKey: rootFieldKey }; diff --git a/packages/dds/tree/src/test/feature-libraries/modular-schema/modularChangeFamily.spec.ts b/packages/dds/tree/src/test/feature-libraries/modular-schema/modularChangeFamily.spec.ts index b55ea3d191a2..fb8c03b5b014 100644 --- a/packages/dds/tree/src/test/feature-libraries/modular-schema/modularChangeFamily.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/modular-schema/modularChangeFamily.spec.ts @@ -71,7 +71,7 @@ import { import { type ValueChangeset, valueField } from "./basicRebasers.js"; import { ajvValidator } from "../../codec/index.js"; -import { jsonObject, singleJsonCursor } from "../../../domains/index.js"; +import { fieldJsonCursor, singleJsonCursor } from "../../json/index.js"; import type { ChangeAtomIdBTree, CrossFieldKeyTable, @@ -422,10 +422,7 @@ const rootChangeWithoutNodeFieldChanges: ModularChangeset = family.compose([ const node1 = singleJsonCursor(1); const objectNode = singleJsonCursor({}); const node1Chunk = treeChunkFromCursor(node1); -const nodesChunk = chunkFieldSingle( - cursorForJsonableTreeField([{ type: jsonObject.name }, { type: jsonObject.name }]), - defaultChunkPolicy, -); +const nodesChunk = chunkFieldSingle(fieldJsonCursor([{}, {}]), defaultChunkPolicy); describe("ModularChangeFamily", () => { describe("compose", () => { diff --git a/packages/dds/tree/src/test/feature-libraries/objectForest.spec.ts b/packages/dds/tree/src/test/feature-libraries/objectForest.spec.ts index f586be70e665..aeec11706907 100644 --- a/packages/dds/tree/src/test/feature-libraries/objectForest.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/objectForest.spec.ts @@ -13,7 +13,7 @@ import { moveToDetachedField, rootFieldKey, } from "../../core/index.js"; -import { singleJsonCursor } from "../../domains/index.js"; +import { singleJsonCursor } from "../json/index.js"; import { cursorForMapTreeNode } from "../../feature-libraries/index.js"; // Allow importing from this specific file which is being tested: /* eslint-disable-next-line import/no-internal-modules */ diff --git a/packages/dds/tree/src/test/feature-libraries/schema-index/codec.spec.ts b/packages/dds/tree/src/test/feature-libraries/schema-index/codec.spec.ts index 37fd00613f9a..c19722e88bd3 100644 --- a/packages/dds/tree/src/test/feature-libraries/schema-index/codec.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/schema-index/codec.spec.ts @@ -16,15 +16,11 @@ import { makeSchemaCodec } from "../../../feature-libraries/schema-index/codec.j /* eslint-disable-next-line import/no-internal-modules */ import { Format } from "../../../feature-libraries/schema-index/format.js"; import { takeJsonSnapshot, useSnapshotDirectory } from "../../snapshots/index.js"; -import { - type EncodingTestData, - jsonPrimitiveSchema, - JsonUnion, - makeEncodingTestSuite, -} from "../../utils.js"; +import { type EncodingTestData, makeEncodingTestSuite } from "../../utils.js"; // eslint-disable-next-line import/no-internal-modules import { toStoredSchema } from "../../../simple-tree/toFlexSchema.js"; import { SchemaFactory } from "../../../simple-tree/index.js"; +import { jsonPrimitiveSchema, JsonUnion } from "../../json/index.js"; const codec = makeSchemaCodec({ jsonValidator: typeboxValidator }); diff --git a/packages/dds/tree/src/test/feature-libraries/schema-index/schemaSummarizer.spec.ts b/packages/dds/tree/src/test/feature-libraries/schema-index/schemaSummarizer.spec.ts index f834b785a8fc..3075d5386416 100644 --- a/packages/dds/tree/src/test/feature-libraries/schema-index/schemaSummarizer.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/schema-index/schemaSummarizer.spec.ts @@ -10,7 +10,7 @@ import { } from "../../../feature-libraries/schema-index/schemaSummarizer.js"; import { toStoredSchema } from "../../../simple-tree/index.js"; import { takeJsonSnapshot, useSnapshotDirectory } from "../../snapshots/index.js"; -import { JsonUnion } from "../../utils.js"; +import { JsonUnion } from "../../json/index.js"; describe("schemaSummarizer", () => { describe("encodeTreeSchema", () => { diff --git a/packages/dds/tree/src/test/feature-libraries/typedSchema/typedTreeSchema.spec.ts b/packages/dds/tree/src/test/feature-libraries/typedSchema/typedTreeSchema.spec.ts index 2f6d5281e0df..f5df740e4b67 100644 --- a/packages/dds/tree/src/test/feature-libraries/typedSchema/typedTreeSchema.spec.ts +++ b/packages/dds/tree/src/test/feature-libraries/typedSchema/typedTreeSchema.spec.ts @@ -5,35 +5,27 @@ import { strict as assert } from "assert"; -import { jsonArray, jsonObject, jsonSchema, leaf } from "../../../domains/index.js"; -import { FieldKinds, SchemaBuilderBase } from "../../../feature-libraries/index.js"; +import { leaf } from "../../../domains/index.js"; +import { FieldKinds } from "../../../feature-libraries/index.js"; import { FlexFieldSchema, - type FlexMapNodeSchema, - type FlexObjectNodeSchema, - type LeafNodeSchema, schemaIsLeaf, schemaIsMap, schemaIsObjectNode, // eslint-disable-next-line import/no-internal-modules } from "../../../feature-libraries/typed-schema/typedTreeSchema.js"; -import type { - isAssignableTo, - requireAssignableTo, - requireFalse, - requireTrue, -} from "../../../util/index.js"; -describe("typedTreeSchema", () => { - const builder = new SchemaBuilderBase(FieldKinds.optional, { - scope: "test", - libraries: [jsonSchema], - }); - const emptyObjectSchema = builder.object("empty", {}); - const basicObjectSchema = builder.object("basicObject", { foo: leaf.number }); +import { SchemaFactory, getFlexSchema } from "../../../simple-tree/index.js"; - const recursiveObject: FlexObjectNodeSchema = builder.object("recursiveObject", { - foo: FlexFieldSchema.create(FieldKinds.optional, [() => recursiveObject]), +describe("typedTreeSchema", () => { + const builder = new SchemaFactory("test"); + const emptyObjectSchema = getFlexSchema(builder.object("empty", {})); + const basicObjectSchema = getFlexSchema( + builder.object("basicObject", { foo: builder.number }), + ); + + const recursiveObject = builder.objectRecursive("recursiveObject", { + foo: builder.optionalRecursive([() => recursiveObject]), }); it("schema is", () => { @@ -41,14 +33,6 @@ describe("typedTreeSchema", () => { assert(!schemaIsObjectNode(leaf.boolean)); assert(!schemaIsMap(leaf.boolean)); - assert(!schemaIsLeaf(jsonArray)); - assert(schemaIsObjectNode(jsonArray)); - assert(!schemaIsMap(jsonArray)); - - assert(!schemaIsLeaf(jsonObject)); - assert(!schemaIsObjectNode(jsonObject)); - assert(schemaIsMap(jsonObject)); - assert(!schemaIsLeaf(emptyObjectSchema)); assert(schemaIsObjectNode(emptyObjectSchema)); assert(!schemaIsMap(emptyObjectSchema)); @@ -56,10 +40,6 @@ describe("typedTreeSchema", () => { assert(!schemaIsLeaf(basicObjectSchema)); assert(schemaIsObjectNode(basicObjectSchema)); assert(!schemaIsMap(basicObjectSchema)); - - assert(!schemaIsLeaf(recursiveObject)); - assert(schemaIsObjectNode(recursiveObject)); - assert(!schemaIsMap(recursiveObject)); }); describe("TreeFieldSchema", () => { @@ -76,36 +56,4 @@ describe("typedTreeSchema", () => { assert.deepEqual(schema.types, new Set([leaf.number.name])); }); }); - - { - type _1 = requireAssignableTo; - type _3 = requireAssignableTo; - type _4 = requireAssignableTo; - type _5 = requireAssignableTo; - } - - { - type _1 = requireTrue>; - type _3 = requireFalse>; - type _4 = requireFalse>; - } - - { - type _1 = requireFalse>; - type _3 = requireFalse>; - // TODO: Fix - // type _4 = requireFalse> - } - - { - type _1 = requireFalse>; - type _3 = requireTrue>; - type _4 = requireFalse>; - } - - { - type _1 = requireFalse>; - type _3 = requireFalse>; - type _4 = requireTrue>; - } }); diff --git a/packages/dds/tree/src/test/forestTestSuite.ts b/packages/dds/tree/src/test/forestTestSuite.ts index 7eb7ba2444d5..28a3188d315b 100644 --- a/packages/dds/tree/src/test/forestTestSuite.ts +++ b/packages/dds/tree/src/test/forestTestSuite.ts @@ -29,7 +29,7 @@ import { moveToDetachedField, rootFieldKey, } from "../core/index.js"; -import { cursorToJsonObject, leaf, singleJsonCursor } from "../domains/index.js"; +import { leaf } from "../domains/index.js"; import { typeboxValidator } from "../external-utilities/index.js"; import { cursorForJsonableTreeNode, @@ -48,12 +48,12 @@ import { applyTestDelta, expectEqualFieldPaths, expectEqualPaths, - JsonArray, - jsonSequenceRootSchema, testIdCompressor, testRevisionTagCodec, } from "./utils.js"; import { cursorFromInsertable, SchemaFactory, toFlexSchema } from "../simple-tree/index.js"; +import { jsonSequenceRootSchema } from "./sequenceRootUtils.js"; +import { cursorToJsonObject, JsonArray, singleJsonCursor } from "./json/index.js"; /** * Configuration for the forest test suite. @@ -569,7 +569,7 @@ export function testForest(config: ForestTestConfiguration): void { }); it("editing a cloned forest does not modify the original", () => { - const schema = new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)); + const schema = new TreeStoredSchemaRepository(jsonSequenceRootSchema); const forest = factory(schema); const content: JsonableTree[] = [ { type: leaf.number.name, value: 1 }, @@ -604,9 +604,7 @@ export function testForest(config: ForestTestConfiguration): void { describe("can apply deltas with", () => { if (!config.skipCursorErrorCheck) { it("ensures cursors are cleared before applying changes", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); initializeForest( forest, [singleJsonCursor(1)], @@ -622,9 +620,7 @@ export function testForest(config: ForestTestConfiguration): void { }); it("ensures cursors created in events during delta processing are cleared", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); initializeForest( forest, [singleJsonCursor(1)], @@ -647,9 +643,7 @@ export function testForest(config: ForestTestConfiguration): void { } it("beforeChange events", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); initializeForest( forest, [singleJsonCursor(1)], @@ -669,9 +663,7 @@ export function testForest(config: ForestTestConfiguration): void { }); it("set fields as remove and insert", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); initializeForest( forest, [singleJsonCursor(nestedContent)], @@ -712,9 +704,7 @@ export function testForest(config: ForestTestConfiguration): void { }); it("set fields as replace", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); initializeForest( forest, [singleJsonCursor(nestedContent)], @@ -879,9 +869,7 @@ export function testForest(config: ForestTestConfiguration): void { }); it("move out and move in", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); initializeForest( forest, [singleJsonCursor(nestedContent)], @@ -918,9 +906,7 @@ export function testForest(config: ForestTestConfiguration): void { }); it("insert and modify", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); const content: JsonCompatible[] = [1, 2]; initializeForest( forest, @@ -988,9 +974,7 @@ export function testForest(config: ForestTestConfiguration): void { }); it("modify and remove", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); initializeForest( forest, [singleJsonCursor(nestedContent)], @@ -1018,9 +1002,7 @@ export function testForest(config: ForestTestConfiguration): void { }); it("modify and move out", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); initializeForest( forest, [singleJsonCursor(nestedContent)], @@ -1084,9 +1066,7 @@ export function testForest(config: ForestTestConfiguration): void { describe("Does not leave an empty field", () => { it("when removing the last node in the field", () => { - const forest = factory( - new TreeStoredSchemaRepository(intoStoredSchema(jsonSequenceRootSchema)), - ); + const forest = factory(new TreeStoredSchemaRepository(jsonSequenceRootSchema)); const delta: DeltaFieldMap = new Map([ [ rootFieldKey, diff --git a/packages/dds/tree/src/domains/json/index.ts b/packages/dds/tree/src/test/json/index.ts similarity index 69% rename from packages/dds/tree/src/domains/json/index.ts rename to packages/dds/tree/src/test/json/index.ts index 5646db35b780..a1cf793ca8a6 100644 --- a/packages/dds/tree/src/domains/json/index.ts +++ b/packages/dds/tree/src/test/json/index.ts @@ -8,4 +8,4 @@ export { cursorToJsonObject, fieldJsonCursor, } from "./jsonCursor.js"; -export { jsonSchema, jsonObject, jsonArray, jsonRoot } from "./jsonDomainSchema.js"; +export { JsonUnion, JsonArray, JsonObject, jsonPrimitiveSchema } from "./jsonDomainSchema.js"; diff --git a/packages/dds/tree/src/domains/json/jsonCursor.ts b/packages/dds/tree/src/test/json/jsonCursor.ts similarity index 83% rename from packages/dds/tree/src/domains/json/jsonCursor.ts rename to packages/dds/tree/src/test/json/jsonCursor.ts index a30c87bedf82..410110513bf0 100644 --- a/packages/dds/tree/src/domains/json/jsonCursor.ts +++ b/packages/dds/tree/src/test/json/jsonCursor.ts @@ -20,11 +20,17 @@ import { stackTreeFieldCursor, stackTreeNodeCursor, } from "../../feature-libraries/index.js"; -import { isReadonlyArray, type JsonCompatible } from "../../util/index.js"; -import { leaf } from "../leafDomain.js"; +import { brand, isReadonlyArray, type JsonCompatible } from "../../util/index.js"; -import { jsonArray, jsonObject } from "./jsonDomainSchema.js"; +import { JsonArray, JsonObject } from "./jsonDomainSchema.js"; import { isFluidHandle } from "@fluidframework/runtime-utils/internal"; +import { + booleanSchema, + nullSchema, + numberSchema, + stringSchema, + // eslint-disable-next-line import/no-internal-modules +} from "../../simple-tree/leafNodeSchema.js"; const adapter: CursorAdapter = { value: (node: JsonCompatible) => @@ -36,18 +42,18 @@ const adapter: CursorAdapter = { switch (type) { case "number": - return leaf.number.name; + return brand(numberSchema.identifier); case "string": - return leaf.string.name; + return brand(stringSchema.identifier); case "boolean": - return leaf.boolean.name; + return brand(booleanSchema.identifier); default: if (node === null) { - return leaf.null.name; + return brand(nullSchema.identifier); } else if (isReadonlyArray(node)) { - return jsonArray.name; + return brand(JsonArray.identifier); } else { - return jsonObject.name; + return brand(JsonObject.identifier); } } }, @@ -121,19 +127,19 @@ export function cursorToJsonObject(reader: ITreeCursor): JsonCompatible { const type = reader.type; switch (type) { - case leaf.number.name: - case leaf.boolean.name: - case leaf.string.name: + case numberSchema.identifier: + case booleanSchema.identifier: + case stringSchema.identifier: assert(reader.value !== undefined, 0x84f /* out of schema: missing value */); assert(!isFluidHandle(reader.value), 0x850 /* out of schema: unexpected FluidHandle */); return reader.value; - case jsonArray.name: { + case JsonArray.identifier: { reader.enterField(EmptyKey); const result = mapCursorField(reader, cursorToJsonObject); reader.exitField(); return result; } - case jsonObject.name: { + case JsonObject.identifier: { const result: JsonCompatible = {}; mapCursorFields(reader, (cursor) => { const key = cursor.getFieldKey(); @@ -150,7 +156,7 @@ export function cursorToJsonObject(reader: ITreeCursor): JsonCompatible { return result; } default: { - assert(type === leaf.null.name, 0x422 /* unexpected type */); + assert(type === nullSchema.identifier, 0x422 /* unexpected type */); return null; } } diff --git a/packages/dds/tree/src/test/json/jsonDomainSchema.ts b/packages/dds/tree/src/test/json/jsonDomainSchema.ts new file mode 100644 index 000000000000..c8ce75c90072 --- /dev/null +++ b/packages/dds/tree/src/test/json/jsonDomainSchema.ts @@ -0,0 +1,13 @@ +/*! + * Copyright (c) Microsoft Corporation and contributors. All rights reserved. + * Licensed under the MIT License. + */ + +import { SchemaFactory } from "../../simple-tree/index.js"; + +const sf = new SchemaFactory("com.fluidframework.json"); + +export const jsonPrimitiveSchema = [sf.null, sf.boolean, sf.number, sf.string] as const; +export const JsonUnion = [() => JsonObject, () => JsonArray, ...jsonPrimitiveSchema] as const; +export class JsonObject extends sf.mapRecursive("object", JsonUnion) {} +export class JsonArray extends sf.arrayRecursive("array", JsonUnion) {} diff --git a/packages/dds/tree/src/test/scalableTestTrees.ts b/packages/dds/tree/src/test/scalableTestTrees.ts index 683a9e81ba65..2ec63314ab55 100644 --- a/packages/dds/tree/src/test/scalableTestTrees.ts +++ b/packages/dds/tree/src/test/scalableTestTrees.ts @@ -12,14 +12,8 @@ import { moveToDetachedField, rootFieldKey, } from "../core/index.js"; -import { jsonSchema, leaf } from "../domains/index.js"; -import { - FieldKinds, - FlexFieldSchema, - SchemaBuilderBase, - type FlexObjectNodeSchema, - type FlexTreeNode, -} from "../feature-libraries/index.js"; +import { leaf } from "../domains/index.js"; +import { FieldKinds, type FlexTreeNode } from "../feature-libraries/index.js"; import type { FlexTreeView, TreeContent } from "../shared-tree/index.js"; import { brand } from "../util/index.js"; import { @@ -30,7 +24,7 @@ import { // eslint-disable-next-line import/no-internal-modules import type { TreeStoredContent } from "../shared-tree/schematizeTree.js"; // eslint-disable-next-line import/no-internal-modules -import { toStoredSchema } from "../simple-tree/toFlexSchema.js"; +import { getFlexSchema, toFlexSchema, toStoredSchema } from "../simple-tree/toFlexSchema.js"; /** * Test trees which can be parametrically scaled to any size. @@ -41,27 +35,6 @@ import { toStoredSchema } from "../simple-tree/toFlexSchema.js"; */ export const localFieldKey: FieldKey = brand("foo"); -const deepBuilder = new SchemaBuilderBase(FieldKinds.required, { - scope: "scalable", - name: "sharedTree.bench: deep", - libraries: [jsonSchema], -}); - -// Test data in "deep" mode: a linked list with a number at the end. -const linkedListSchema: FlexObjectNodeSchema = deepBuilder.object("linkedList", { - foo: FlexFieldSchema.create(FieldKinds.required, [() => linkedListSchema, leaf.number]), -}); - -const wideBuilder = new SchemaBuilderBase(FieldKinds.required, { - scope: "scalable", - name: "sharedTree.bench: wide", - libraries: [jsonSchema], -}); - -export const wideRootSchema = wideBuilder.object("WideRoot", { - [EmptyKey]: FlexFieldSchema.create(FieldKinds.sequence, [leaf.number]), -}); - const sf = new SchemaFactory("scalable"); /** @@ -83,16 +56,6 @@ export class LinkedList extends sf.objectRecursive("linkedList", { */ export class WideRoot extends sf.array("WideRoot", sf.number) {} -/** - * @deprecated Use {@link WideRoot}. - */ -export const wideSchema = wideBuilder.intoSchema(wideRootSchema); - -/** - * @deprecated Use {@link LinkedList}. - */ -export const deepSchema = deepBuilder.intoSchema([linkedListSchema, leaf.number]); - export interface JSDeepTree { foo: JSDeepTree | number; } @@ -110,7 +73,7 @@ export function makeDeepContent(depth: number, leafValue: number = 1): TreeConte // Types do not allow implicitly constructing recursive types, so cast is required. // TODO: Find a better alternative. initialTree: cursorFromInsertable(LinkedList, initialTree as LinkedList), - schema: deepSchema, + schema: toFlexSchema(LinkedList), }; } @@ -142,7 +105,7 @@ export function makeWideContentWithEndValue( const initialTree = makeJsWideTreeWithEndValue(numberOfNodes, endLeafValue); return { initialTree: cursorFromInsertable(WideRoot, initialTree), - schema: wideSchema, + schema: toFlexSchema(WideRoot), }; } @@ -293,7 +256,7 @@ export function readWideFlexTree(tree: FlexTreeView): { assert(root.is(FieldKinds.required)); const field = (root.content as FlexTreeNode).getBoxed(EmptyKey); assert(field.length !== 0); - assert(field.isExactly(wideRootSchema.info[EmptyKey])); + assert(field.is(FieldKinds.sequence)); for (const currentNode of field.boxedIterator()) { sum += currentNode.value as number; nodesCount += 1; @@ -308,7 +271,7 @@ export function readDeepFlexTree(tree: FlexTreeView): { let depth = 0; assert(tree.flexTree.is(FieldKinds.required)); let currentNode = tree.flexTree.content as FlexTreeNode; - while (currentNode.is(linkedListSchema)) { + while (currentNode.is(getFlexSchema(LinkedList))) { const read = currentNode.getBoxed(brand("foo")); assert(read.is(FieldKinds.required)); currentNode = read.content as FlexTreeNode; diff --git a/packages/dds/tree/src/test/sequenceRootUtils.ts b/packages/dds/tree/src/test/sequenceRootUtils.ts index 190da1e5c704..b2d0a346dda1 100644 --- a/packages/dds/tree/src/test/sequenceRootUtils.ts +++ b/packages/dds/tree/src/test/sequenceRootUtils.ts @@ -9,19 +9,20 @@ import { type MapTree, type TreeNodeSchemaIdentifier, } from "../core/index.js"; -import { leaf, singleJsonCursor } from "../domains/index.js"; +import { leaf } from "../domains/index.js"; import { FieldKinds, cursorForMapTreeField } from "../feature-libraries/index.js"; import type { ITreeCheckout } from "../shared-tree/index.js"; import { toStoredSchema } from "../simple-tree/index.js"; import { brand, type JsonCompatible } from "../util/index.js"; -import { checkoutWithContent, JsonUnion } from "./utils.js"; +import { checkoutWithContent } from "./utils.js"; // eslint-disable-next-line import/no-internal-modules import { normalizeAllowedTypes } from "../simple-tree/schemaTypes.js"; +import { JsonUnion, singleJsonCursor } from "./json/index.js"; // This file provides utilities for testing sequence fields using documents where the root is the sequence being tested. // This pattern is not expressible using the public simple-tree API, and is only for testing internal details. -const rootJsonSequenceSchema: TreeStoredSchema = { +export const jsonSequenceRootSchema: TreeStoredSchema = { nodeSchema: toStoredSchema(JsonUnion).nodeSchema, rootFieldSchema: { kind: FieldKinds.sequence.identifier, @@ -64,7 +65,7 @@ export function remove(tree: ITreeCheckout, index: number, count: number): void export function makeTreeFromJsonSequence(json: JsonCompatible[]): ITreeCheckout { const cursors = json.map(singleJsonCursor); const tree = checkoutWithContent({ - schema: rootJsonSequenceSchema, + schema: jsonSequenceRootSchema, initialTree: cursors, }); return tree; diff --git a/packages/dds/tree/src/test/shared-tree-core/edit-manager/editManager.bench.ts b/packages/dds/tree/src/test/shared-tree-core/edit-manager/editManager.bench.ts index a6a5a928e65f..a98e18013a13 100644 --- a/packages/dds/tree/src/test/shared-tree-core/edit-manager/editManager.bench.ts +++ b/packages/dds/tree/src/test/shared-tree-core/edit-manager/editManager.bench.ts @@ -13,7 +13,6 @@ import { rootFieldKey, type ChangeFamilyEditor, } from "../../../core/index.js"; -import { singleJsonCursor } from "../../../domains/index.js"; import { DefaultChangeFamily } from "../../../feature-libraries/index.js"; import type { Commit } from "../../../shared-tree-core/index.js"; import { brand } from "../../../util/index.js"; @@ -28,6 +27,7 @@ import { rebaseLocalEditsOverTrunkEdits, rebasePeerEditsOverTrunkEdits, } from "./editManagerTestUtils.js"; +import { singleJsonCursor } from "../../json/index.js"; describe("EditManager - Bench", () => { interface Scenario { diff --git a/packages/dds/tree/src/test/shared-tree/editing.spec.ts b/packages/dds/tree/src/test/shared-tree/editing.spec.ts index 5d0eaaad2fab..5489aa696e92 100644 --- a/packages/dds/tree/src/test/shared-tree/editing.spec.ts +++ b/packages/dds/tree/src/test/shared-tree/editing.spec.ts @@ -22,7 +22,7 @@ import { moveToDetachedField, rootFieldKey, } from "../../core/index.js"; -import { jsonObject, leaf, singleJsonCursor } from "../../domains/index.js"; +import { leaf } from "../../domains/index.js"; import { cursorForJsonableTreeNode } from "../../feature-libraries/index.js"; import type { ITreeCheckout, TreeStoredContent } from "../../shared-tree/index.js"; import { type JsonCompatible, brand, makeArray } from "../../util/index.js"; @@ -30,13 +30,13 @@ import { checkoutWithContent, createTestUndoRedoStacks, expectJsonTree, - JsonUnion, makeTreeFromJson, moveWithin, validateUsageError, } from "../utils.js"; import { insert, makeTreeFromJsonSequence, remove } from "../sequenceRootUtils.js"; import { SchemaFactory, toStoredSchema } from "../../simple-tree/index.js"; +import { JsonUnion, singleJsonCursor } from "../json/index.js"; const rootField: FieldUpPath = { parent: undefined, @@ -246,9 +246,7 @@ describe("Editing", () => { const tree3 = tree1.fork(); insert(tree2, 1, "C"); - tree3.editor - .sequenceField(rootField) - .insert(0, cursorForJsonableTreeNode({ type: jsonObject.name })); + tree3.editor.sequenceField(rootField).insert(0, singleJsonCursor({})); const aEditor = tree3.editor.sequenceField({ parent: rootNode, field: brand("foo") }); aEditor.insert(0, cursorForJsonableTreeNode({ type: leaf.string.name, value: "a" })); @@ -501,12 +499,10 @@ describe("Editing", () => { insert(tree1, 0, "a"); expectJsonTree(tree1, ["a"]); - tree2.editor - .sequenceField(rootField) - .insert(0, cursorForJsonableTreeNode({ type: jsonObject.name })); + tree2.editor.sequenceField(rootField).insert(0, singleJsonCursor({})); tree2.editor .sequenceField({ parent: rootNode, field: brand("foo") }) - .insert(0, cursorForJsonableTreeNode({ type: jsonObject.name })); + .insert(0, singleJsonCursor({})); expectJsonTree(tree2, [{ foo: {} }]); tree2.rebaseOnto(tree1); @@ -1555,7 +1551,7 @@ describe("Editing", () => { parent: rootNode, field: brand("src"), }); - field.set(cursorForJsonableTreeNode({ type: jsonObject.name })); + field.set(singleJsonCursor({})); tree.transaction.commit(); const expectedState: JsonCompatible = [{ src: {}, dst: ["A", "B"] }]; @@ -2597,7 +2593,7 @@ describe("Editing", () => { const { undoStack, unsubscribe } = createTestUndoRedoStacks(tree.events); const rootSequence = tree.editor.sequenceField(rootField); - rootSequence.insert(0, cursorForJsonableTreeNode({ type: jsonObject.name })); + rootSequence.insert(0, singleJsonCursor({})); const treeSequence = tree.editor.sequenceField({ parent: rootNode, field: brand("foo"), @@ -2637,7 +2633,7 @@ describe("Editing", () => { const tree = checkoutWithContent(emptyJsonContent); const rootSequence = tree.editor.sequenceField(rootField); - rootSequence.insert(0, cursorForJsonableTreeNode({ type: jsonObject.name })); + rootSequence.insert(0, singleJsonCursor({})); const treeSequence = tree.editor.sequenceField({ parent: rootNode, field: brand("foo"), @@ -2734,7 +2730,7 @@ describe("Editing", () => { it("optional field node exists constraint", () => { const tree = checkoutWithContent(emptyJsonContent); const rootSequence = tree.editor.sequenceField(rootField); - rootSequence.insert(0, cursorForJsonableTreeNode({ type: jsonObject.name })); + rootSequence.insert(0, singleJsonCursor({})); const optional = tree.editor.optionalField({ parent: rootNode, field: brand("foo"), @@ -2767,7 +2763,7 @@ describe("Editing", () => { const tree = checkoutWithContent(emptyJsonContent); const { undoStack, unsubscribe } = createTestUndoRedoStacks(tree.events); const rootSequence = tree.editor.sequenceField(rootField); - rootSequence.insert(0, cursorForJsonableTreeNode({ type: jsonObject.name })); + rootSequence.insert(0, singleJsonCursor({})); const optional = tree.editor.optionalField({ parent: rootNode, @@ -2874,7 +2870,7 @@ describe("Editing", () => { it("a change can depend on the existence of a node that is built in a prior change whose constraint was violated", () => { const tree = checkoutWithContent(emptyJsonContent); const rootSequence = tree.editor.sequenceField(rootField); - rootSequence.insert(0, cursorForJsonableTreeNode({ type: jsonObject.name })); + rootSequence.insert(0, singleJsonCursor({})); const optional = tree.editor.optionalField({ parent: rootNode, field: brand("foo"), @@ -2988,7 +2984,7 @@ describe("Editing", () => { parentIndex: 0, }); const tree2RootSequence = tree2.editor.sequenceField(rootField); - tree2RootSequence.insert(2, cursorForJsonableTreeNode({ type: jsonObject.name })); + tree2RootSequence.insert(2, singleJsonCursor({})); tree2.transaction.commit(); tree.merge(tree2, false); diff --git a/packages/dds/tree/src/test/shared-tree/schematizeTree.spec.ts b/packages/dds/tree/src/test/shared-tree/schematizeTree.spec.ts index 6278c71c31ec..f9bfea2e3200 100644 --- a/packages/dds/tree/src/test/shared-tree/schematizeTree.spec.ts +++ b/packages/dds/tree/src/test/shared-tree/schematizeTree.spec.ts @@ -15,7 +15,7 @@ import { TreeStoredSchemaRepository, type AnchorSetRootEvents, } from "../../core/index.js"; -import { singleJsonCursor } from "../../domains/index.js"; +import { singleJsonCursor } from "../json/index.js"; import { FieldKinds, FlexFieldSchema, @@ -41,15 +41,12 @@ import { initializeContent, // eslint-disable-next-line import/no-internal-modules } from "../../shared-tree/schematizeTree.js"; -import { - checkoutWithContent, - jsonSequenceRootSchema, - validateViewConsistency, -} from "../utils.js"; +import { checkoutWithContent, validateViewConsistency } from "../utils.js"; import type { Listenable } from "../../events/index.js"; import { SchemaFactory } from "../../simple-tree/index.js"; // eslint-disable-next-line import/no-internal-modules import { toStoredSchema } from "../../simple-tree/toFlexSchema.js"; +import { jsonSequenceRootSchema } from "../sequenceRootUtils.js"; const builder = new SchemaFactory("test"); const root = builder.number; @@ -194,8 +191,8 @@ describe("schematizeTree", () => { ["basic-optional-empty", schema, true], ["basic-optional", schema, false], ["basic-value", schemaValueRoot, false], - ["complex-empty", intoStoredSchema(jsonSequenceRootSchema), true], - ["complex", intoStoredSchema(jsonSequenceRootSchema), false], + ["complex-empty", jsonSequenceRootSchema, true], + ["complex", jsonSequenceRootSchema, false], ]; for (const [name, data, isEmpty] of testCases) { it(name, () => { diff --git a/packages/dds/tree/src/test/shared-tree/sharedTree.bench.ts b/packages/dds/tree/src/test/shared-tree/sharedTree.bench.ts index 8299a69599f0..4af635983936 100644 --- a/packages/dds/tree/src/test/shared-tree/sharedTree.bench.ts +++ b/packages/dds/tree/src/test/shared-tree/sharedTree.bench.ts @@ -13,7 +13,7 @@ import { } from "@fluid-tools/benchmark"; import { EmptyKey, rootFieldKey } from "../../core/index.js"; -import { singleJsonCursor } from "../../domains/index.js"; +import { singleJsonCursor } from "../json/index.js"; // eslint-disable-next-line import/no-internal-modules import { typeboxValidator } from "../../external-utilities/typeboxValidator.js"; import { diff --git a/packages/dds/tree/src/test/shared-tree/sharedTree.spec.ts b/packages/dds/tree/src/test/shared-tree/sharedTree.spec.ts index 8d1d5532bd3f..49974051e38f 100644 --- a/packages/dds/tree/src/test/shared-tree/sharedTree.spec.ts +++ b/packages/dds/tree/src/test/shared-tree/sharedTree.spec.ts @@ -31,7 +31,7 @@ import { type ChangeFamilyEditor, EmptyKey, } from "../../core/index.js"; -import { leaf, singleJsonCursor } from "../../domains/index.js"; +import { leaf } from "../../domains/index.js"; import { typeboxValidator } from "../../external-utilities/index.js"; import { ChunkedForest, @@ -90,7 +90,6 @@ import { validateViewConsistency, validateUsageError, StringArray, - JsonArray, NumberArray, } from "../utils.js"; import { configuredSharedTree } from "../../treeFactory.js"; @@ -98,6 +97,7 @@ import type { ISharedObjectKind } from "@fluidframework/shared-object-base/inter import { TestAnchor } from "../testAnchor.js"; // eslint-disable-next-line import/no-internal-modules import { stringSchema } from "../../simple-tree/leafNodeSchema.js"; +import { JsonArray, singleJsonCursor } from "../json/index.js"; const enableSchemaValidation = true; diff --git a/packages/dds/tree/src/test/shared-tree/sharedTreeChangeEnricher.spec.ts b/packages/dds/tree/src/test/shared-tree/sharedTreeChangeEnricher.spec.ts index dfebf649a0e5..78e375d56e36 100644 --- a/packages/dds/tree/src/test/shared-tree/sharedTreeChangeEnricher.spec.ts +++ b/packages/dds/tree/src/test/shared-tree/sharedTreeChangeEnricher.spec.ts @@ -15,7 +15,7 @@ import { mapCursorField, rootFieldKey, } from "../../core/index.js"; -import { cursorToJsonObject, singleJsonCursor } from "../../domains/index.js"; +import { cursorToJsonObject, singleJsonCursor } from "../json/index.js"; import { typeboxValidator } from "../../external-utilities/index.js"; // eslint-disable-next-line import/no-internal-modules import { optional } from "../../feature-libraries/default-schema/defaultFieldKinds.js"; diff --git a/packages/dds/tree/src/test/shared-tree/undo.spec.ts b/packages/dds/tree/src/test/shared-tree/undo.spec.ts index 50b34e502f9a..b5942bbb776c 100644 --- a/packages/dds/tree/src/test/shared-tree/undo.spec.ts +++ b/packages/dds/tree/src/test/shared-tree/undo.spec.ts @@ -4,7 +4,7 @@ */ import { type UpPath, rootFieldKey } from "../../core/index.js"; -import { singleJsonCursor } from "../../domains/index.js"; +import { singleJsonCursor } from "../json/index.js"; import type { ITreeCheckout } from "../../shared-tree/index.js"; import { type JsonCompatible, brand } from "../../util/index.js"; import { createTestUndoRedoStacks, expectJsonTree, moveWithin } from "../utils.js"; diff --git a/packages/dds/tree/src/test/testTrees.ts b/packages/dds/tree/src/test/testTrees.ts index 9c8d1c35c7a0..1321111ed1de 100644 --- a/packages/dds/tree/src/test/testTrees.ts +++ b/packages/dds/tree/src/test/testTrees.ts @@ -39,7 +39,7 @@ import { // eslint-disable-next-line import/no-internal-modules import { jsonableTreesFromFieldCursor } from "./feature-libraries/chunked-forest/fieldCursorTestUtilities.js"; // eslint-disable-next-line import/no-internal-modules -import { fieldJsonCursor } from "../domains/json/jsonCursor.js"; +import { fieldJsonCursor } from "./json/jsonCursor.js"; interface TestTree { readonly name: string; diff --git a/packages/dds/tree/src/test/utils.ts b/packages/dds/tree/src/test/utils.ts index 7a8f16cf2fc3..6e610d146213 100644 --- a/packages/dds/tree/src/test/utils.ts +++ b/packages/dds/tree/src/test/utils.ts @@ -87,20 +87,11 @@ import { type ITreeCursorSynchronous, CursorLocationType, } from "../core/index.js"; -import { - cursorToJsonObject, - jsonRoot, - jsonSchema, - leaf, - singleJsonCursor, -} from "../domains/index.js"; import type { HasListeners, IEmitter, Listenable } from "../events/index.js"; import { typeboxValidator } from "../external-utilities/index.js"; import { - FieldKinds, type FlexFieldSchema, type NodeKeyManager, - SchemaBuilderBase, ViewSchema, buildForest, cursorForMapTreeNode, @@ -160,6 +151,7 @@ import { 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"; // Testing utilities @@ -768,21 +760,6 @@ export const IdentifierSchema = sf.object("identifier-object", { identifier: sf.identifier, }); -export const jsonPrimitiveSchema = [sf.null, sf.boolean, sf.number, sf.string] as const; -export const JsonUnion = [() => JsonObject, () => JsonArray, ...jsonPrimitiveSchema] as const; -export const JsonObject = sf.mapRecursive("object", JsonUnion); -export const JsonArray = sf.arrayRecursive("array", JsonUnion); - -export const jsonSequenceRootSchema = new SchemaBuilderBase(FieldKinds.sequence, { - scope: "JsonSequenceRoot", - libraries: [jsonSchema], -}).intoSchema(jsonRoot); - -export const numberSequenceRootSchema = new SchemaBuilderBase(FieldKinds.sequence, { - libraries: [leaf.library], - scope: "NumberSequenceRoot", -}).intoSchema(leaf.number); - /** * Crates a tree using the Json domain with a required root field. */