/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { PrimitiveValueSchema, TreeSchemaIdentifier, ValueSchema } from "../../core";
import { ContextuallyTypedNodeData, MarkedArrayLike, PrimitiveValue, typeNameSymbol, valueSymbol } from "../contextuallyTyped";
import { Multiplicity } from "../modular-schema";
import { InternalTypedSchemaTypes, FieldSchema, TreeSchema, AllowedTypes } from "../typed-schema";
import { UntypedField, UntypedTree, UntypedTreeCore } from "../untypedTree";
import { Assume, FlattenKeys, _InlineTrick } from "../../util";
import { UntypedOptionalField, UntypedSequenceField, UntypedValueField } from "./partlyTyped";
import { TypedValue, TypedValueOrUndefined } from "./schemaAwareUtil";
/**
 * Empty Object for use in type computations that should contribute no fields when `&`ed with another type.
 * @alpha
 */
export declare type EmptyObject = {};
/**
 * @alpha
 */
export declare type ValuePropertyFromSchema<TSchema extends ValueSchema | undefined> = TSchema extends ValueSchema ? {
    [valueSymbol]: TypedValue<TSchema>;
} : EmptyObject;
/**
 * Different schema aware APIs that can be generated.
 * @alpha
 */
export declare const enum ApiMode {
    /**
     * Allow all forms accepted as ContextuallyTypedNodeData that align with the schema.
     * Types are optional.
     *
     * This also permits some cases which are ambiguous and thus would be rejected by `applyFieldTypesFromContext`.
     */
    Flexible = 0,
    /**
     * Similar to what EditableTree uses.
     * No flexibility in representation.
     * Fields are unwrapped (see `EditableUnwrapped`).
     *
     * TODO: fix ways this differs from editable tree:
     * - Does not do primary field inlining.
     * - Primitive node handling might not match.
     */
    Editable = 1,
    /**
     * Editable, but primitive nodes are unwrapped to the primitive values.
     */
    EditableUnwrapped = 2,
    /**
     * Always use full node objects for everything.
     *
     * Fields are still shaped based on their multiplicity.
     *
     * TODO: test and fix
     */
    Wrapped = 3,
    /**
     * Simplified version of Flexible.
     *
     * Primitive values are always unwrapped.
     */
    Simple = 4
}
/**
 * Collects the various parts of the API together.
 * @alpha
 */
export declare type CollectOptions<Mode extends ApiMode, TTypedFields, TValueSchema extends ValueSchema | undefined, TName> = {
    [ApiMode.Flexible]: EmptyObject extends TTypedFields ? TypedValueOrUndefined<TValueSchema> | FlexibleObject<TValueSchema, TName> : FlexibleObject<TValueSchema, TName> & TTypedFields;
    [ApiMode.Editable]: {
        [typeNameSymbol]: TName & TreeSchemaIdentifier;
    } & ValuePropertyFromSchema<TValueSchema> & TTypedFields & UntypedTreeCore;
    [ApiMode.EditableUnwrapped]: [EmptyObject, TValueSchema] extends [
        TTypedFields,
        PrimitiveValueSchema
    ] ? TypedValueOrUndefined<TValueSchema> : CollectOptions<ApiMode.Editable, TTypedFields, TValueSchema, TName>;
    [ApiMode.Wrapped]: {
        [typeNameSymbol]: TName;
        [valueSymbol]: TypedValueOrUndefined<TValueSchema>;
    } & TTypedFields;
    [ApiMode.Simple]: EmptyObject extends TTypedFields ? TypedValueOrUndefined<TValueSchema> : FlexibleObject<TValueSchema, TName> & TTypedFields;
}[Mode];
/**
 * The name and value part of the `Flexible` API.
 * @alpha
 */
export declare type FlexibleObject<TValueSchema extends ValueSchema | undefined, TName> = [
    FlattenKeys<{
        [typeNameSymbol]?: UnbrandedName<TName>;
    } & ValuePropertyFromSchema<TValueSchema>>
][_InlineTrick];
/**
 * Remove type brand from name.
 * @alpha
 */
export declare type UnbrandedName<TName> = [
    TName extends infer S & TreeSchemaIdentifier ? S : string
][_InlineTrick];
/**
 * `{ [key: string]: FieldSchemaTypeInfo }` to `{ [key: string]: TypedTree }`
 *
 * In Editable mode, unwraps the fields.
 * @alpha
 */
export declare type TypedFields<Mode extends ApiMode, TFields extends undefined | {
    [key: string]: FieldSchema;
}> = [
    TFields extends {
        [key: string]: FieldSchema;
    } ? {
        [key in keyof TFields]: TypedField<TFields[key], Mode extends ApiMode.Editable ? ApiMode.EditableUnwrapped : Mode>;
    } : EmptyObject
][_InlineTrick];
/**
 * `FieldSchema` to `TypedField`. May unwrap to child depending on Mode and FieldKind.
 * @alpha
 */
export declare type TypedField<TField extends FieldSchema, Mode extends ApiMode = ApiMode.Editable> = [
    ApplyMultiplicity<TField["kind"]["multiplicity"], AllowedTypesToTypedTrees<Mode, TField["allowedTypes"]>, Mode>
][_InlineTrick];
/**
 * Adjusts the API for a field based on its Multiplicity.
 * @alpha
 */
export declare type ApplyMultiplicity<TMultiplicity extends Multiplicity, TypedChild, Mode extends ApiMode> = {
    [Multiplicity.Forbidden]: undefined;
    [Multiplicity.Optional]: Mode extends ApiMode.Editable ? EditableOptionalField<TypedChild> : undefined | TypedChild;
    [Multiplicity.Sequence]: Mode extends ApiMode.Editable | ApiMode.EditableUnwrapped ? EditableSequenceField<TypedChild> : TypedChild[];
    [Multiplicity.Value]: Mode extends ApiMode.Editable ? EditableValueField<TypedChild> : TypedChild;
}[TMultiplicity];
export declare type EditableField<TypedChild> = UntypedField & MarkedArrayLike<TypedChild>;
/**
 * @alpha
 */
export declare type EditableSequenceField<TypedChild> = [
    UntypedSequenceField & MarkedArrayLike<TypedChild>
][_InlineTrick];
/**
 * @alpha
 */
export declare type EditableValueField<TypedChild> = [
    UntypedValueField & MarkedArrayLike<TypedChild>
][_InlineTrick];
/**
 * @alpha
 */
export declare type EditableOptionalField<TypedChild> = [
    UntypedOptionalField & MarkedArrayLike<TypedChild>
][_InlineTrick];
/**
 * Takes in `AllowedTypes` and returns a TypedTree union.
 * @alpha
 */
export declare type AllowedTypesToTypedTrees<Mode extends ApiMode, T extends AllowedTypes> = [
    T extends InternalTypedSchemaTypes.FlexList<TreeSchema> ? InternalTypedSchemaTypes.ArrayToUnion<TypeArrayToTypedTreeArray<Mode, Assume<InternalTypedSchemaTypes.ConstantFlexListToNonLazyArray<T>, readonly TreeSchema[]>>> : UntypedApi<Mode>
][_InlineTrick];
/**
 * Takes in `TreeSchema[]` and returns a TypedTree union.
 * @alpha
 */
export declare type TypeArrayToTypedTreeArray<Mode extends ApiMode, T extends readonly TreeSchema[]> = [
    T extends readonly [infer Head, ...infer Tail] ? [
        TypedNode<Assume<Head, TreeSchema>, Mode>,
        ...TypeArrayToTypedTreeArray<Mode, Assume<Tail, readonly TreeSchema[]>>
    ] : []
][_InlineTrick];
/**
 * API if type is unknown or Any.
 * @alpha
 */
export declare type UntypedApi<Mode extends ApiMode> = {
    [ApiMode.Editable]: UntypedTree;
    [ApiMode.EditableUnwrapped]: UntypedTree | PrimitiveValue;
    [ApiMode.Flexible]: ContextuallyTypedNodeData;
    [ApiMode.Simple]: ContextuallyTypedNodeData;
    [ApiMode.Wrapped]: UntypedTree;
}[Mode];
/**
 * Generate a schema aware API for a single tree schema.
 * @alpha
 */
export declare type TypedNode<TSchema extends TreeSchema, Mode extends ApiMode = ApiMode.Editable> = FlattenKeys<CollectOptions<Mode, TypedFields<Mode extends ApiMode.Editable ? ApiMode.EditableUnwrapped : Mode, TSchema["structFieldsObject"]>, TSchema["leafValue"], TSchema["name"]>>;
/**
 * Generate a schema aware API for a single tree schema.
 * @alpha
 * @deprecated Use `TypedNode` instead (and reverse the type parameter order).
 */
export declare type NodeDataFor<Mode extends ApiMode, TSchema extends TreeSchema> = TypedNode<TSchema, Mode>;
/**
 * Check if an `UntypedTreeCore` has a specific schema, and if it does, cast it to use `ApiMode.Editable` with that schema.
 * Provided schema must be included in the schema for the tree being viewed (getting this wrong will error).
 * @alpha
 */
export declare function downCast<TSchema extends TreeSchema>(schema: TSchema, tree: UntypedTreeCore<any, any>): tree is TypedNode<TSchema>;
//# sourceMappingURL=schemaAware.d.ts.map