/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { type Adapters, type FieldKey, type StoredSchemaCollection, type TreeFieldStoredSchema, type TreeNodeSchemaIdentifier, type TreeNodeStoredSchema, type TreeStoredSchema, type TreeTypeSet, type ValueSchema } from "../../core/index.js";
import { type MakeNominal, type Named } from "../../util/index.js";
import { FieldKinds } from "../default-schema/index.js";
import type { FlexFieldKind, FullSchemaPolicy } from "../modular-schema/index.js";
import type { LazyItem } from "./flexList.js";
/**
 */
export interface FlexObjectNodeFields {
    readonly [key: string]: FlexFieldSchema;
}
/**
 * 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}.
 *
 * These extends constraints only serve as documentation:
 * to avoid breaking compilation, this type has to not actually enforce anything, and thus is just `unknown`.
 * Therefore the type safety is the responsibility of the user of the API.
 * @public
 */
export type Unenforced<_DesiredExtendsConstraint> = unknown;
/**
 * T must extend TreeSchemaSpecification.
 * This can not be enforced using TypeScript since doing so breaks recursive type support.
 * See note on SchemaBuilder.fieldRecursive.
 */
export declare abstract class TreeNodeSchemaBase<const out Specification = unknown> {
    readonly builder: Named<string>;
    readonly name: TreeNodeSchemaIdentifier;
    readonly info: Specification;
    readonly stored: TreeNodeStoredSchema;
    protected _typeCheck: MakeNominal;
    protected constructor(builder: Named<string>, name: TreeNodeSchemaIdentifier, info: Specification, stored: TreeNodeStoredSchema);
    abstract getFieldSchema(field: FieldKey): FlexFieldSchema;
}
/**
 */
export declare class FlexMapNodeSchema extends TreeNodeSchemaBase {
    get mapFields(): FlexMapFieldSchema;
    protected _typeCheck2?: MakeNominal;
    static create<const Name extends string>(builder: Named<string>, name: TreeNodeSchemaIdentifier<Name>, specification: FlexMapFieldSchema): FlexMapNodeSchema;
    getFieldSchema(field: FieldKey): FlexMapFieldSchema;
}
/**
 */
export declare class LeafNodeSchema extends TreeNodeSchemaBase<ValueSchema> {
    protected _typeCheck2?: MakeNominal;
    constructor(builder: Named<string>, name: string, specification: ValueSchema);
    getFieldSchema(field: FieldKey): FlexFieldSchema;
}
/**
 */
export declare class FlexObjectNodeSchema extends TreeNodeSchemaBase {
    readonly objectNodeFieldsObject: FlexObjectNodeFields;
    readonly objectNodeFields: ReadonlyMap<FieldKey, FlexFieldSchema>;
    protected _typeCheck2?: MakeNominal;
    readonly identifierFieldKeys: readonly FieldKey[];
    static create(builder: Named<string>, name: TreeNodeSchemaIdentifier, specification: FlexObjectNodeFields): FlexObjectNodeSchema;
    private constructor();
    getFieldSchema(field: FieldKey): FlexFieldSchema;
}
/**
 * @privateRemarks
 * This could be an exhaustive union, or just the common base type.
 * Using just the base type prevents exhaustive matching, which has both pros and cons.
 *
 * For now this is using just the base type since the union is causing issues with schema aware typing, likely due to it being a union and thus distributing over extends clauses.
 */
export type FlexTreeNodeSchema = TreeNodeSchemaBase;
/**
 * 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.
 */
export type LazyTreeNodeSchema = FlexTreeNodeSchema | (() => FlexTreeNodeSchema);
/**
 * Types for use in fields.
 */
export type FlexAllowedTypes = readonly LazyItem<FlexTreeNodeSchema>[];
/**
 * Subset of TreeFieldSchema thats legal in maps.
 * This requires empty to be a valid value for the map.
 */
export type FlexMapFieldSchema = FlexFieldSchema<typeof FieldKinds.optional | typeof FieldKinds.sequence>;
/**
 * 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.
 *
 * @remarks
 * `Types` here must extend `AllowedTypes`, but this cannot be enforced with an "extends" clause: see {@link Unenforced} for details.
 *
 * @typeParam TKind - The kind of field.
 * @typeParam TTypes - The types allowed by the field.
 *
 * @sealed
 */
export declare class FlexFieldSchema<out TKind extends FlexFieldKind = FlexFieldKind> {
    readonly kind: TKind;
    readonly allowedTypes: FlexAllowedTypes;
    /**
     * Schema for a field which must always be empty.
     */
    static readonly empty: FlexFieldSchema<import("../default-schema/defaultFieldKinds.js").Forbidden>;
    /**
     * Constructs a TreeFieldSchema.
     * @privateRemarks
     * Alias for the constructor, but with extends clause for the `Types` parameter that {@link FlexFieldSchema} can not have (due to recursive type issues).
     */
    static create<TKind extends FlexFieldKind>(kind: TKind, allowedTypes: FlexAllowedTypes): FlexFieldSchema<TKind>;
    protected _typeCheck: MakeNominal;
    /**
     * This is computed lazily since types can be recursive, which makes evaluating this have to happen after all the schema are defined.
     */
    private readonly lazyTypes;
    /**
     * @param kind - The {@link https://en.wikipedia.org/wiki/Kind_(type_theory) | kind} of this field.
     * Determine the multiplicity, viewing and editing APIs as well as the merge resolution policy.
     * @param allowedTypes - What types of tree nodes are allowed in this field.
     */
    private constructor();
    readonly stored: TreeFieldStoredSchema;
    /**
     * Types which are allowed in this field (by {@link TreeNodeSchemaIdentifier}), in a format optimized for stored schema.
     * This is the same set of types in {@link FlexFieldSchema.allowedTypes}, just in a different format.
     */
    get types(): TreeTypeSet;
    /**
     * Types which are allowed in this field.
     * This is the same set of types in {@link FlexFieldSchema.allowedTypes}, just as a set with laziness removed.
     * @privateRemarks
     * TODO:
     * 3 ways to access the allowed types are now exposed.
     * Reducing this and/or renaming the more friendly options to take the shorter name (`types`)
     * would be a good idea.
     */
    get allowedTypeSet(): AllowedTypeSet;
    /**
     * If exactly one type of child is allowed in this field, it is provided here.
     * @remarks
     * Some code paths (like unboxing and compressed tree encoding) special case schema with exactly one allowed type.
     * This field allows for simple and optimized handling of this case.
     */
    get monomorphicChildType(): FlexTreeNodeSchema | undefined;
    /**
     * Compare this schema to another.
     *
     * @returns true iff the schema are identical.
     */
    equals(other: FlexFieldSchema): boolean;
}
/**
 * Types for use in fields.
 * This representation is optimized for runtime use in view-schema.
 *
 * @remarks
 * See {@link TreeTypeSet} for a stored-schema compatible version using the {@link TreeNodeSchemaIdentifier}.
 * See {@link FlexAllowedTypes} for a compile time optimized version.
 */
export type AllowedTypeSet = ReadonlySet<FlexTreeNodeSchema>;
/**
 * Convert {@link FlexAllowedTypes} to {@link TreeTypeSet}.
 */
export declare function allowedTypesSchemaSet(t: FlexAllowedTypes): AllowedTypeSet;
/**
 * Convert {@link FlexAllowedTypes} to {@link TreeTypeSet}.
 */
export declare function allowedTypesToTypeSet(t: FlexAllowedTypes): TreeTypeSet;
/**
 * Schema data that can be be used to view a document.
 * Strongly typed over its rootFieldSchema.
 *
 * @remarks
 * The type of the rootFieldSchema is used to implement SchemaAware APIs.
 * Cases that do not require being compile time schema aware can omit the explicit type for it.
 */
export interface FlexTreeSchema<out T extends FlexFieldSchema = FlexFieldSchema> extends SchemaCollection {
    /**
     * Schema for the root field which contains the whole tree.
     */
    readonly rootFieldSchema: T;
    /**
     * Extra configuration for how this schema is handled at runtime.
     */
    readonly policy: FullSchemaPolicy;
    /**
     * Compatibility information how how to interact with content who's stored schema is not directly compatible with this schema.
     */
    readonly adapters: Adapters;
}
/**
 * Converts a {@link FlexTreeSchema} into a {@link TreeStoredSchema}.
 */
export declare function intoStoredSchema(treeSchema: FlexTreeSchema): TreeStoredSchema;
/**
 * Converts a {@link SchemaCollection} into a {@link StoredSchemaCollection}.
 */
export declare function intoStoredSchemaCollection(treeSchema: SchemaCollection): StoredSchemaCollection;
/**
 * Schema data that can be be used to view a document.
 *
 * @privateRemarks
 * It is convenient that this can be used as a StoredSchemaCollection with no conversion.
 * There there isn't a design requirement for this however, so this extends clause can be removed later if needed.
 */
export interface SchemaCollection {
    /**
     * {@inheritdoc SchemaCollection}
     */
    readonly nodeSchema: ReadonlyMap<TreeNodeSchemaIdentifier, FlexTreeNodeSchema>;
}
/**
 * Checks if a {@link FlexTreeNodeSchema} is a {@link FlexMapNodeSchema}.
 */
export declare function schemaIsMap(schema: FlexTreeNodeSchema): schema is FlexMapNodeSchema;
/**
 * Checks if a {@link FlexTreeNodeSchema} is a {@link LeafNodeSchema}.
 */
export declare function schemaIsLeaf(schema: FlexTreeNodeSchema): schema is LeafNodeSchema;
/**
 * Checks if a {@link FlexTreeNodeSchema} is a {@link FlexObjectNodeSchema}.
 */
export declare function schemaIsObjectNode(schema: FlexTreeNodeSchema): schema is FlexObjectNodeSchema;
//# sourceMappingURL=typedTreeSchema.d.ts.map