/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { RestrictiveReadonlyRecord } from "../util";
import { FlexTreeNode } from "../feature-libraries";
import { TreeListNode, TreeMapNodeBase } from "../simple-tree";
import { AllowedTypes, FieldKind, FieldSchema, ImplicitAllowedTypes, ImplicitFieldSchema, InsertableObjectFromSchemaRecord, InsertableTreeNodeFromImplicitAllowedTypes, InsertableTypedNode, NodeFromSchema, NodeKind, ObjectFromSchemaRecord, TreeNodeFromImplicitAllowedTypes, TreeNodeSchema, TreeNodeSchemaClass } from "./schemaTypes";
/**
 * 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 @beta
 */
export declare class SchemaFactory<TScope extends 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>;
    /**
     * {@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>;
    /**
     * {@link TreeNodeSchema} for holding a boolean.
     */
    readonly boolean: TreeNodeSchema<"com.fluidframework.leaf.boolean", NodeKind.Leaf, 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 provide 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>;
    /**
     * {@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>>;
    /**
     * 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, ObjectFromSchemaRecord<T>, InsertableObjectFromSchemaRecord<T>>;
    /**
     * Define a structurally typed {@link TreeNodeSchema} for a {@link TreeMapNodeBase}.
     *
     * @remarks
     * The {@link TreeNodeSchemaIdentifier} 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 list.
     */
    map<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchema<`${TScope}.Map<${string}>`, NodeKind.Map, TreeMapNodeBase<TreeNodeFromImplicitAllowedTypes<T>>, ReadonlyMap<string, TreeNodeFromImplicitAllowedTypes<T>>>;
    /**
     * 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, TreeMapNodeBase<TreeNodeFromImplicitAllowedTypes<T>>, ReadonlyMap<string, TreeNodeFromImplicitAllowedTypes<T>>>;
    private namedMap;
    /**
     * Define a structurally typed {@link TreeNodeSchema} for a {@link (TreeListNode:interface)}.
     *
     * @remarks
     * The identifier for this List 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 lists, other types in this schema builder should avoid names of the form `List<${string}>`.
     *
     * @example
     * The returned schema should be used as a schema directly:
     * ```typescript
     * const MyList = factory.list(factory.number);
     * type MyList = NodeFromSchema<typeof MyList>;
     * ```
     * Or inline:
     * ```typescript
     * factory.object("Foo", {myList: factory.list(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 lists 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.
     */
    list<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchema<`${TScope}.List<${string}>`, NodeKind.List, TreeListNode<T>, Iterable<TreeNodeFromImplicitAllowedTypes<T>>>;
    /**
     * Define (and add to this library) a {@link FieldNodeSchema} for a {@link (TreeListNode:interface)}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     *
     * @example
     * ```typescript
     * class NamedList extends factory.list("name", factory.number) {}
     * ```
     */
    list<const Name extends TName, const T extends ImplicitAllowedTypes>(name: Name, allowedTypes: T): TreeNodeSchemaClass<`${TScope}.${Name}`, NodeKind.List, TreeListNode<T>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>>;
    /**
     * Define a {@link TreeNodeSchema} for a {@link (TreeListNode:interface)}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     */
    private namedList;
    /**
     * 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.
     * The command `TypeScript: Restart TS Server` should fix it.
     * Sometimes this does not work: the exact cause has not been confirmed but if you have the file open multiple times (for example in both sides of a window split into two columns): closing the extra copy may help.
     * Focusing the file with the errors before running `TypeScript: Restart TS Server` can also 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`.
     *
     * @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