/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { strict as assert } from "assert";
import { unreachableCase } from "@fluidframework/core-utils";
import { jsonArray, jsonObject, jsonSchema, leaf, SchemaBuilder, } from "../../../domains/index.js";
import { EmptyKey } from "../../../core/index.js";
import { FieldKinds, Any, FlexFieldSchema, } from "../../../feature-libraries/index.js";
describe("editableTreeTypes", () => {
    /**
     * Example showing narrowing and exhaustive matches.
     */
    function exhaustiveMatchSimple(root) {
        const schema = SchemaBuilder.required([() => leaf.number, leaf.string]);
        assert(root.is(schema));
        const tree = root.boxedContent;
        if (tree.is(leaf.number)) {
            const n = tree.value;
        }
        else if (tree.is(leaf.string)) {
            const s = tree.value;
        }
        else {
            // Proves at compile time exhaustive match checking works, and tree is typed `never`.
            unreachableCase(tree);
        }
    }
    /**
     * Example showing the node kinds used in the json domain (everything except structs),
     * including narrowing and exhaustive matches.
     */
    function jsonExample(root) {
        // Rather than using jsonSequenceRootSchema.rootFieldSchema, recreate an equivalent schema.
        // Doing this avoids a compile error (but not an intellisense error) on unreachableCase below.
        // This has not be fully root caused, but it likely due to to schema d.ts files for recursive types containing `any` due to:
        // https://github.com/microsoft/TypeScript/issues/55832
        const jsonPrimitives = [...leaf.primitives, leaf.null];
        const jsonRoot2 = [() => jsonObject, () => jsonArray, ...jsonPrimitives];
        const schema = SchemaBuilder.sequence(jsonRoot2);
        assert(root.is(schema));
        for (const tree of root.boxedIterator()) {
            if (tree.is(leaf.boolean)) {
                const b = tree.value;
            }
            else if (tree.is(leaf.number)) {
                const n = tree.value;
            }
            else if (tree.is(leaf.string)) {
                const s = tree.value;
            }
            else if (tree.is(jsonArray)) {
                const a = tree.content;
                jsonExample(a);
            }
            else if (tree.is(jsonObject)) {
                const x = tree.get(EmptyKey);
            }
            else if (tree.is(leaf.null)) {
                const x = tree.value;
            }
            else {
                // Proves at compile time exhaustive match checking works, and tree is typed `never`.
                unreachableCase(tree);
            }
        }
    }
    const builder = new SchemaBuilder({ scope: "test", libraries: [jsonSchema] });
    const emptyStruct = builder.object("empty", {});
    const basicStruct = builder.object("basicObject", { foo: builder.optional(Any) });
    const basicFieldNode = builder.fieldNode("field", builder.optional(Any));
    // TODO: once schema kinds are separated, test struct with EmptyKey.
    const mixedStruct = builder.object("mixedStruct", {
        /**
         * Test doc comment.
         */
        leaf: leaf.number,
        polymorphic: [leaf.number, leaf.string],
        optionalLeaf: builder.optional(leaf.number),
        optionalObject: SchemaBuilder.optional(jsonObject),
        sequence: SchemaBuilder.sequence(leaf.number),
    });
    const recursiveStruct = builder.objectRecursive("recursiveStruct", {
        /**
         * Test Recursive Field.
         */
        foo: FlexFieldSchema.createUnsafe(FieldKinds.optional, [() => recursiveStruct]),
        /**
         * Data field.
         */
        x: SchemaBuilder.required(leaf.number),
    });
    /**
     * All combinations of boxed and unboxed access.
     */
    function boxingExample(mixed) {
        const leafNode = mixed.leaf;
        const leafBoxed = mixed.boxedLeaf.boxedContent;
        // Current policy is to box polymorphic values so they can be checked for type with `is`.
        // Note that this still unboxes the value field.
        const polymorphic = mixed.polymorphic;
        // Fully boxed, including the value field.
        const boxedPolymorphic = mixed.boxedPolymorphic;
        const optionalLeaf = mixed.optionalLeaf;
        const boxedOptionalLeaf = mixed.boxedOptionalLeaf.boxedContent;
        const sequence = mixed.sequence;
        const child = sequence.at(0);
        const childBoxed = sequence.boxedAt(0);
    }
    function recursiveStructExample(struct) {
        const child = struct.foo;
        const data = struct.x + (struct.foo?.foo?.foo?.x ?? 0);
        assert(child);
        child.foo?.foo?.foo?.foo?.setX(5);
        child.foo?.boxedFoo.content?.foo?.foo?.setFoo({ x: 5, foo: { x: 5, foo: undefined } });
        struct.boxedFoo.content = undefined;
        // Shorthand for the above.
        struct.setFoo(undefined);
        struct.foo = undefined;
    }
    function iteratorsExample(mixed) {
        const unboxedListIteration = [...mixed.sequence];
        const boxedListIteration = [
            ...mixed.sequence.boxedIterator(),
        ];
        const optionalNumberField = SchemaBuilder.optional(leaf.number);
        const mapSchema = undefined;
        const mapNode = undefined;
        const unboxedMapIteration = [...mapNode];
        const boxedMapIteration = [
            ...mapNode.boxedIterator(),
        ];
    }
    {
    }
    {
    }
    {
        // TODO: Fix
        // type _4 = requireFalse<isAssignableTo<typeof jsonArray, ObjectNodeSchema>>
    }
    {
    }
    {
    }
    function nominalTyping() {
        const builder2 = new SchemaBuilder({ scope: "test" });
        const emptyStruct1 = builder2.object("empty1", {});
        const emptyStruct2 = builder2.object("empty2", {});
        // Schema for types which only different in name are distinguished
        {
        }
        // Schema for TypedNode which only different in name are distinguished
        {
        }
    }
    {
    }
    // Basic unit test for TreeNode.is type narrowing.
    function nodeIs(node) {
        if (node.is(basicStruct)) {
        }
        if (node.is(basicFieldNode)) {
        }
    }
    // TypedNodeUnion
    {
        // Any
        {
        }
        // Direct
        {
        }
        // Lazy
        {
        }
        // Union
        {
        }
        // Recursive
        {
        }
        // Recursive Lazy
        {
        }
        // Type-Erased
        {
        }
    }
    // UnboxNodeUnion
    {
        // Any
        {
        }
        // Direct
        {
        }
        // Lazy
        {
        }
        // Union
        {
        }
        // Unboxed FieldNode
        {
        }
        // Recursive
        {
        }
        // Recursive Lazy
        {
        }
        // Type-Erased
        {
        }
        // Generic
        // eslint-disable-next-line no-inner-declarations
        function genericTest(t) {
        }
    }
    // IsArrayOfOne
    {
    }
});
//# sourceMappingURL=editableTreeTypes.spec.js.map