/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { FieldKey, TreeSchemaIdentifier, TreeTypeSet, ValueSchema } from "../../core";
import { MakeNominal, Assume, RestrictiveReadonlyRecord, _InlineTrick, FlattenKeys, Named } from "../../util";
import { FieldKindTypes, FieldKinds } from "../default-field-kinds";
import { LazyItem } from "./flexList";
import { ObjectToMap, WithDefault } from "./typeUtils";
import { RecursiveTreeSchemaSpecification } from "./schemaBuilder";
/**
 * @public
 */
export interface Fields {
    readonly [key: string]: FieldSchema;
}
/**
 * @public
 */
export declare type NormalizeStructFieldsInner<T extends Fields> = {
    [Property in keyof T]: NormalizeField<T[Property]>;
};
/**
 * @public
 */
export declare type NormalizeStructFields<T extends Fields | undefined> = NormalizeStructFieldsInner<WithDefault<T, Record<string, never>>>;
/**
 * T must extend TreeSchemaSpecification.
 * This can not be enforced using TypeScript since doing so breaks recursive type support.
 * See note on SchemaBuilder.fieldRecursive.
 * @public
 */
export declare class TreeSchema<Name extends string = string, T extends RecursiveTreeSchemaSpecification = TreeSchemaSpecification> {
    readonly builder: Named<string>;
    readonly structFields: ObjectToMap<NormalizeStructFields<Assume<T, TreeSchemaSpecification>["structFields"]>, FieldKey, FieldSchema>;
    readonly structFieldsObject: NormalizeStructFields<Assume<T, TreeSchemaSpecification>["structFields"]>;
    readonly mapFields: WithDefault<Assume<T, TreeSchemaSpecification>["mapFields"], undefined>;
    readonly leafValue: WithDefault<Assume<T, TreeSchemaSpecification>["leafValue"], undefined>;
    readonly name: Name & TreeSchemaIdentifier;
    readonly info: Assume<T, TreeSchemaSpecification>;
    constructor(builder: Named<string>, name: Name, info: T);
}
/**
 * @public
 */
export declare type MapSchema = TreeSchema & MapSchemaSpecification;
/**
 * @public
 */
export declare type LeafSchema = TreeSchema & LeafSchemaSpecification;
/**
 * TODO: this includes FieldNodeSchema when it shouldn't
 * @public
 */
export declare type StructSchema = TreeSchema & {
    [P in keyof (MapSchemaSpecification & LeafSchemaSpecification)]?: undefined;
};
/**
 * This is the subset of StructSchema that uses {@link EmptyKey} so the the old (editable-tree 1) API unboxes it.
 * TODO: Once that API is removed, this can be cleaned up and properly separated from StructSchema
 * @public
 */
export declare type FieldNodeSchema = StructSchema & {
    /**
     * The fields of this node.
     * Only uses the {@link EmptyKey}.
     *
     * TODO: this extra indirection will be removed when refactoring TreeSchema (see other related TODOs for details).
     */
    structFieldsObject: {
        /**
         * The field this node wraps.
         * It is under the {@link EmptyKey}.
         */
        [""]: FieldSchema;
    };
};
export declare function schemaIsMap(schema: TreeSchema): schema is MapSchema;
export declare function schemaIsLeaf(schema: TreeSchema): schema is LeafSchema;
export declare function schemaIsFieldNode(schema: TreeSchema): schema is FieldNodeSchema;
export declare function schemaIsStruct(schema: TreeSchema): schema is StructSchema;
/**
 * Convert FieldSchemaSpecification | undefined into FieldSchema.
 * @public
 */
export declare type NormalizeField<T extends FieldSchema | undefined> = T extends FieldSchema ? T : FieldSchema<typeof FieldKinds.forbidden, []>;
/**
 * Allow any node (as long as it meets the schema for its own type).
 * @public
 */
export declare const Any: "Any";
/**
 * Allow any node (as long as it meets the schema for its own type).
 * @public
 */
export declare type Any = typeof Any;
/**
 * Tree type, but can be wrapped in a function to allow referring to types before they are declared.
 * This makes recursive and co-recursive types possible.
 * @public
 */
export declare type LazyTreeSchema = TreeSchema | (() => TreeSchema);
/**
 * Types for use in fields.
 *
 * "Any" is boxed in an array to allow use as variadic parameter.
 * @public
 */
export declare type AllowedTypes = [Any] | readonly LazyItem<TreeSchema>[];
/**
 * Checks if an {@link AllowedTypes} is {@link (Any:type)}.
 * @public
 */
export declare function allowedTypesIsAny(t: AllowedTypes): t is [Any];
/**
 * `TreeSchemaSpecification` for {@link SchemaBuilder.struct}.
 * @public
 */
export interface StructSchemaSpecification {
    readonly structFields: RestrictiveReadonlyRecord<string, FieldSchema>;
}
/**
 * `TreeSchemaSpecification` for {@link SchemaBuilder.map}.
 * @public
 */
export interface MapSchemaSpecification {
    readonly mapFields: MapFieldSchema;
}
/**
 * Subset of FieldSchema thats legal in maps.
 * This requires empty to be a valid value for the map.
 * @public
 */
export declare type MapFieldSchema = FieldSchema<typeof FieldKinds.optional | typeof FieldKinds.sequence>;
/**
 * `TreeSchemaSpecification` for {@link SchemaBuilder.leaf}.
 * @public
 */
export interface LeafSchemaSpecification {
    readonly leafValue: ValueSchema;
}
/**
 * Object for capturing information about a TreeStoredSchema for use at both compile time and runtime.
 * @public
 */
export declare type TreeSchemaSpecification = [
    FlattenKeys<(StructSchemaSpecification | MapSchemaSpecification | LeafSchemaSpecification) & Partial<StructSchemaSpecification & MapSchemaSpecification & LeafSchemaSpecification>>
][_InlineTrick];
/**
 * All policy for a specific field,
 * including functionality that does not have to be kept consistent across versions or deterministic.
 *
 * This can include policy for how to use this schema for "view" purposes, and well as how to expose editing APIs.
 * @sealed @public
 */
export declare class FieldSchema<Kind extends FieldKindTypes = FieldKindTypes, Types = AllowedTypes> {
    readonly kind: Kind;
    readonly allowedTypes: Types;
    /**
     * Schema for a field which must always be empty.
     */
    static readonly empty: FieldSchema<import("../default-field-kinds").Forbidden, never[]>;
    protected _typeCheck?: MakeNominal;
    constructor(kind: Kind, allowedTypes: Types);
    get types(): TreeTypeSet;
}
/**
 * Convert {@link AllowedTypes} to {@link TreeTypeSet}.
 * @public
 */
export declare function allowedTypesToTypeSet(t: AllowedTypes): TreeTypeSet;
//# sourceMappingURL=typedTreeSchema.d.ts.map