/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import type { FieldKey, SchemaPolicy } from "../core/index.js";
import { type FlexTreeField } from "../feature-libraries/index.js";
import { type ImplicitFieldSchema, type TreeFieldFromImplicitField, type InsertableTreeFieldFromImplicitField, type FieldSchema, type ImplicitAllowedTypes, FieldKind, type NodeSchemaMetadata, type GetTypes, type SchemaUnionToIntersection } from "./schemaTypes.js";
import { NodeKind, type WithType, type TreeNode } from "./core/index.js";
import { type InsertableContent } from "./toMapTree.js";
import { type RestrictiveStringRecord, type FlattenKeys } from "../util/index.js";
import { type ObjectNodeSchema, type ObjectNodeSchemaInternalData } from "./objectNodeTypes.js";
/**
 * Generates the properties for an ObjectNode from its field schema object.
 * @system @public
 */
export type ObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = {
    -readonly [Property in keyof T as [
        AssignableTreeFieldFromImplicitField<T[Property & string]>
    ] extends [never | undefined] ? never : Property]: AssignableTreeFieldFromImplicitField<T[Property & string]>;
} & {
    readonly [Property in keyof T]: TreeFieldFromImplicitField<T[Property & string]>;
};
/**
 * Type of content that can be assigned to a field of the given schema.
 *
 * @see {@link Input}
 *
 * @typeparam TSchemaInput - Schema to process.
 * @typeparam TSchema - Do not specify: default value used as an implementation detail.
 * @system @public
 */
export type AssignableTreeFieldFromImplicitField<TSchemaInput extends ImplicitFieldSchema, TSchema = SchemaUnionToIntersection<TSchemaInput>> = [TSchema] extends [FieldSchema<infer Kind, infer Types>] ? ApplyKindAssignment<GetTypes<Types>["readWrite"], Kind> : [TSchema] extends [ImplicitAllowedTypes] ? GetTypes<TSchema>["readWrite"] : never;
/**
 * Suitable for assignment.
 *
 * @see {@link Input}
 * @system @public
 */
export type ApplyKindAssignment<T, Kind extends FieldKind> = [Kind] extends [
    FieldKind.Required
] ? T : [Kind] extends [FieldKind.Optional] ? T | undefined : never;
/**
 * A {@link TreeNode} which modules a JavaScript object.
 * @remarks
 * Object nodes consist of a type which specifies which {@link TreeNodeSchema} they use (see {@link TreeNodeApi.schema}), and a collections of fields, each with a distinct `key` and its own {@link FieldSchema} defining what can be placed under that key.
 *
 * All fields on an object node are exposed as own properties with string keys.
 * Non-empty fields are enumerable and empty optional fields are non-enumerable own properties with the value `undefined`.
 * No other own `own` or `enumerable` properties are included on object nodes unless the user of the node manually adds custom session only state.
 * This allows a majority of general purpose JavaScript object processing operations (like `for...in`, `Reflect.ownKeys()` and `Object.entries()`) to enumerate all the children.
 * @public
 */
export type TreeObjectNode<T extends RestrictiveStringRecord<ImplicitFieldSchema>, TypeName extends string = string> = TreeNode & ObjectFromSchemaRecord<T> & WithType<TypeName, NodeKind.Object, T>;
/**
 * Type utility for determining whether or not an implicit field schema has a default value.
 *
 * @privateRemarks
 * TODO: Account for field schemas with default value providers.
 * For now, this only captures field kinds that we know always have defaults - optional fields and identifier fields.
 *
 * @system @public
 */
export type FieldHasDefault<T extends ImplicitFieldSchema> = T extends FieldSchema<FieldKind.Optional | FieldKind.Identifier> ? true : false;
/**
 * Helper used to produce types for:
 *
 * 1. Insertable content which can be used to construct an object node.
 * In this case, only own properties are considered.
 * This reduces the risk of incorrectly interpreting data at the cost of occasionally requiring users to convert data into a compatible format.
 *
 * 2. Insertable content which is an unhydrated object node.
 *
 * 3. Union of 1 and 2.
 *
 * @see {@link Input}
 *
 * @privateRemarks
 * TODO: consider separating these cases into different types.
 *
 * Empty objects don't get "no excess property" checks in literals.
 * To prevent extraneous properties in literals for the fields of an empty object from compiling, the empty case is special cased to produce `Record<string, never>`.
 * More details at {@link https://mercury.com/blog/creating-an-emptyobject-type-in-typescript}.
 *
 * @system @public
 */
export type InsertableObjectFromSchemaRecord<T extends RestrictiveStringRecord<ImplicitFieldSchema>> = Record<string, never> extends T ? Record<string, never> : FlattenKeys<{
    readonly [Property in keyof T]?: InsertableTreeFieldFromImplicitField<T[Property & string]>;
} & {
    readonly [Property in keyof T as FieldHasDefault<T[Property & string]> extends false ? Property : never]: InsertableTreeFieldFromImplicitField<T[Property & string]>;
}>;
/**
 * Maps from simple field keys ("property" keys) to information about the field.
 *
 * @remarks
 * A missing entry for a given property key indicates that no such field exists.
 * Keys with symbols are currently never used, but allowed to make lookups on non-field things
 * (returning undefined) easier.
 */
export type SimpleKeyMap = ReadonlyMap<string | symbol, {
    storedKey: FieldKey;
    schema: FieldSchema;
}>;
export declare function setField(field: FlexTreeField, simpleFieldSchema: FieldSchema, value: InsertableContent | undefined): void;
/**
 * Define a {@link TreeNodeSchema} for a {@link TreeObjectNode}.
 *
 * @param name - Unique identifier for this schema within this factory's scope.
 * @param fields - Schema for fields of the object node's schema. Defines what children can be placed under each key.
 */
export declare function objectSchema<TName extends string, const T extends RestrictiveStringRecord<ImplicitFieldSchema>, const ImplicitlyConstructable extends boolean, const TCustomMetadata = unknown>(identifier: TName, info: T, implicitlyConstructable: ImplicitlyConstructable, allowUnknownOptionalFields: boolean, metadata?: NodeSchemaMetadata<TCustomMetadata>): ObjectNodeSchema<TName, T, ImplicitlyConstructable, TCustomMetadata> & ObjectNodeSchemaInternalData;
/**
 * Creates a policy for allowing unknown optional fields on an object node which delegates to the policy defined
 * on the object node's internal schema data.
 */
export declare function createUnknownOptionalFieldPolicy(schema: ImplicitFieldSchema): SchemaPolicy["allowUnknownOptionalFields"];
//# sourceMappingURL=objectNode.d.ts.map