/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { RestrictiveReadonlyRecord } from "../util";
import { FlexTreeNode } from "../feature-libraries";
import { TreeValue } from "../core";
import { TreeArrayNode, TreeNode } from "../simple-tree";
import { AllowedTypes, FieldKind, FieldSchema, ImplicitAllowedTypes, ImplicitFieldSchema, InsertableObjectFromSchemaRecord, InsertableTreeNodeFromImplicitAllowedTypes, InsertableTypedNode, NodeFromSchema, NodeKind, ObjectFromSchemaRecord, TreeMapNode, TreeNodeFromImplicitAllowedTypes, TreeNodeSchema, TreeNodeSchemaClass, WithType } from "./schemaTypes";
/**
 * Gets the leaf domain schema compatible with a given {@link TreeValue}.
 */
export declare function schemaFromValue(value: TreeValue): TreeNodeSchema;
/**
 * Builds schema libraries, and the schema within them.
 *
 * @typeParam TScope - Scope added as a prefix to the name of every schema produced by this factory.
 * @typeParam TName - Type of names used to identify each schema produced in this factory.
 * Typically this is just `string` but it is also possible to use `string` or `number` based enums if you prefer to identify your types that way.
 *
 * @sealed @public
 */
export declare class SchemaFactory<TScope extends string = string, TName extends number | string = string> {
    readonly scope: TScope;
    private readonly structuralTypes;
    /**
     * @param scope - Prefix appended to the identifiers of all {@link TreeNodeSchema} produced by this builder.
     * Use of [Reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation) or a UUIDv4 is recommended to avoid collisions.
     */
    constructor(scope: TScope);
    private scoped;
    /**
     * {@link TreeNodeSchema} for holding a JavaScript `string`.
     *
     * @remarks
     * Strings containing unpaired UTF-16 surrogate pair code units may not be handled correctly.
     *
     * These limitations come from the use of UTF-8 encoding of the strings, which requires them to be valid unicode.
     * JavaScript does not make this requirement for its strings so not all possible JavaScript strings are supported.
     * @privateRemarks
     * TODO:
     * We should be much more clear about what happens if you use problematic values.
     * We should validate and/or normalize them when inserting content.
     */
    readonly string: TreeNodeSchema<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string>;
    /**
     * {@link TreeNodeSchema} for holding a JavaScript `number`.
     *
     * @remarks
     * The number is a [double-precision 64-bit binary format IEEE 754](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) value, however there are some exceptions:
     * - `NaN`, and the infinities are converted to `null` (and may therefore only be used where `null` is allowed by the schema).
     * - `-0` may be converted to `0` in some cases.
     *
     * These limitations match the limitations of JSON.
     * @privateRemarks
     * TODO:
     * We should be much more clear about what happens if you use problematic values.
     * We should validate and/or normalize them when inserting content.
     */
    readonly number: TreeNodeSchema<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number>;
    /**
     * {@link TreeNodeSchema} for holding a boolean.
     */
    readonly boolean: TreeNodeSchema<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean>;
    /**
     * {@link TreeNodeSchema} for JavaScript `null`.
     *
     * @remarks
     * There are good [reasons to avoid using null](https://www.npmjs.com/package/%40rushstack/eslint-plugin#rushstackno-new-null) in JavaScript, however sometimes it is desired.
     * This {@link TreeNodeSchema} node provides the option to include nulls in trees when desired.
     * Unless directly inter-operating with existing data using null, consider other approaches, like wrapping the value in an optional field, or using a more specifically named empty object node.
     */
    readonly null: TreeNodeSchema<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null>;
    /**
     * {@link TreeNodeSchema} for holding an {@link @fluidframework/core-interfaces#IFluidHandle}.
     */
    readonly handle: TreeNodeSchema<"com.fluidframework.leaf.handle", NodeKind.Leaf, import("@fluidframework/core-interfaces").IFluidHandle<import("@fluidframework/core-interfaces").FluidObject & import("@fluidframework/core-interfaces").IFluidLoadable>, import("@fluidframework/core-interfaces").IFluidHandle<import("@fluidframework/core-interfaces").FluidObject & import("@fluidframework/core-interfaces").IFluidLoadable>>;
    /**
     * Construct a class that provides the common parts all TreeNodeSchemaClass share.
     * More specific schema extend this class.
     */
    private nodeSchema;
    /**
     * Define a {@link TreeNodeSchema} for an object node.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     */
    object<const Name extends TName, const T extends RestrictiveReadonlyRecord<string, ImplicitFieldSchema>>(name: Name, t: T): TreeNodeSchemaClass<`${TScope}.${Name}`, NodeKind.Object, object & TreeNode & ObjectFromSchemaRecord<T> & WithType<`${TScope}.${Name}`>, object & InsertableObjectFromSchemaRecord<T>, true>;
    /**
     * Define a structurally typed {@link TreeNodeSchema} for a {@link TreeMapNodeBase}.
     *
     * @remarks
     * The unique identifier for this Map is defined as a function of the provided types.
     * It is still scoped to this SchemaBuilder, but multiple calls with the same arguments will return the same schema object, providing somewhat structural typing.
     * This does not support recursive types.
     *
     * If using these structurally named maps, other types in this schema builder should avoid names of the form `Map<${string}>`.
     *
     * @example
     * The returned schema should be used as a schema directly:
     * ```typescript
     * const MyMap = factory.map(factory.number);
     * type MyMap = NodeFromSchema<typeof MyMap>;
     * ```
     * Or inline:
     * ```typescript
     * factory.object("Foo", {myMap: factory.map(factory.number)});
     * ```
     * @privateRemarks
     * See note on array.
     */
    map<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchema<`${TScope}.Map<${string}>`, NodeKind.Map, TreeMapNode<T> & WithType<`${TScope}.Map<${string}>`>, ReadonlyMap<string, TreeNodeFromImplicitAllowedTypes<T>>, true>;
    /**
     * Define a {@link TreeNodeSchema} for a {@link TreeMapNodeBase}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     *
     * @example
     * ```typescript
     * class NamedMap extends factory.map("name", factory.number) {}
     * ```
     */
    map<Name extends TName, const T extends ImplicitAllowedTypes>(name: Name, allowedTypes: T): TreeNodeSchemaClass<`${TScope}.${Name}`, NodeKind.Map, TreeMapNode<T> & WithType<`${TScope}.${Name}`>, ReadonlyMap<string, InsertableTreeNodeFromImplicitAllowedTypes<T>>, true>;
    /**
     * Define a {@link TreeNodeSchema} for a {@link (TreeMapNode:interface)}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     *
     * @remarks See remarks on {@link SchemaFactory.namedArray_internal}.
     */
    namedMap_internal<Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean>(name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable): TreeNodeSchemaClass<`${TScope}.${Name}`, NodeKind.Map, TreeMapNode<T> & WithType<`${TScope}.${Name}`>, ReadonlyMap<string, InsertableTreeNodeFromImplicitAllowedTypes<T>>, ImplicitlyConstructable>;
    /**
     * Define a structurally typed {@link TreeNodeSchema} for a {@link (TreeArrayNode:interface)}.
     *
     * @remarks
     * The identifier for this Array is defined as a function of the provided types.
     * It is still scoped to this SchemaFactory, but multiple calls with the same arguments will return the same schema object, providing somewhat structural typing.
     * This does not support recursive types.
     *
     * If using these structurally named arrays, other types in this schema builder should avoid names of the form `Array<${string}>`.
     *
     * @example
     * The returned schema should be used as a schema directly:
     * ```typescript
     * const MyArray = factory.array(factory.number);
     * type MyArray = NodeFromSchema<typeof MyArray>;
     * ```
     * Or inline:
     * ```typescript
     * factory.object("Foo", {myArray: factory.array(factory.number)});
     * ```
     * @privateRemarks
     * The name produced at the type level here is not as specific as it could be, however doing type level sorting and escaping is a real mess.
     * There are cases where not having this full type provided will be less than ideal since TypeScript's structural types.
     * For example attempts to narrow unions of structural arrays by name won't work.
     * Planned future changes to move to a class based schema system as well as factor function based node construction should mostly avoid these issues,
     * though there may still be some problematic cases even after that work is done.
     *
     * The return value is a class, but its the type is intentionally not specific enough to indicate it is a class.
     * This prevents callers of this from sub-classing it, which is unlikely to work well (due to the ease of accidentally giving two different calls o this different subclasses)
     * when working with structural typing.
     */
    array<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchema<`${TScope}.Array<${string}>`, NodeKind.Array, TreeArrayNode<T> & WithType<`${TScope}.Array<${string}>`>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true>;
    /**
     * Define (and add to this library) a {@link TreeNodeSchemaClass} for a {@link (TreeArrayNode:interface)}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     *
     * @example
     * ```typescript
     * class NamedArray extends factory.array("name", factory.number) {}
     * ```
     */
    array<const Name extends TName, const T extends ImplicitAllowedTypes>(name: Name, allowedTypes: T): TreeNodeSchemaClass<`${TScope}.${Name}`, NodeKind.Array, TreeArrayNode<T> & WithType<`${TScope}.${Name}`>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true>;
    /**
     * Define a {@link TreeNodeSchema} for a {@link (TreeArrayNode:interface)}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     *
     * @remarks
     * This is not intended to be used directly, use the overload of `array` which takes a name instead.
     * This is only public to work around a compiler limitation.
     *
     * @privateRemarks
     * TODO: this should be made private or protected.
     * Doing so breaks due to:
     * `src/class-tree/schemaFactoryRecursive.ts:42:9 - error TS2310: Type 'Array' recursively references itself as a base type.`
     * Once recursive APIs are better sorted out and integrated into this class, switch this back to private.
     */
    namedArray_internal<Name extends TName | string, const T extends ImplicitAllowedTypes, const ImplicitlyConstructable extends boolean>(name: Name, allowedTypes: T, customizable: boolean, implicitlyConstructable: ImplicitlyConstructable): TreeNodeSchemaClass<`${TScope}.${Name}`, NodeKind.Array, TreeArrayNode<T> & WithType<`${TScope}.${string}`>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, ImplicitlyConstructable>;
    /**
     * Make a field optional instead of the default which is required.
     */
    optional<const T extends ImplicitAllowedTypes>(t: T): FieldSchema<FieldKind.Optional, T>;
    /**
     * Function which can be used for its compile time side-effects to tweak the evaluation order of recursive types to make them compile.
     * @remarks
     * Some related information in https://github.com/microsoft/TypeScript/issues/55758.
     *
     * Also be aware that code which relies on this tends to break VSCode's IntelliSense every time anything related to that code (even comments) is edited.
     * Running the command `TypeScript: Restart TS Server` with the schema file focused should fix it.
     * Sometimes this does not work: closing all open files except the schema before running the command can help.
     * Real compile errors (for example elsewhere in the file) can also cause the IntelliSense to not work correctly ever after `TypeScript: Restart TS Server`.
     *
     * Intellisense has also shown problems when schema files with recursive types are part of a cyclic file dependency.
     * Splitting the schema into its own file with minimal dependencies can help with this.
     *
     * Ensure `"noImplicitAny": true` is set in the `tsconfig.json`.
     * Without it, recursive types that are not working properly can infer `any` and give very non-type-safe results instead of erroring.
     *
     * @example
     * ```typescript
     * const factory = new SchemaFactory("example");
     * const recursiveReference = () => RecursiveObject;
     * factory.fixRecursiveReference(recursiveReference);
     * export class RecursiveObject extends factory.object("exampleObject", {
     * 	recursive: [recursiveReference],
     * }) {}
     * ```
     */
    fixRecursiveReference<T extends AllowedTypes>(...types: T): void;
}
export declare function createTree<T extends TreeNodeSchema>(schema: T, data: InsertableTypedNode<T> | FlexTreeNode): NodeFromSchema<T>;
export declare function structuralName<const T extends string>(collectionName: T, allowedTypes: TreeNodeSchema | readonly TreeNodeSchema[]): `${T}<${string}>`;
//# sourceMappingURL=schemaFactory.d.ts.map