import { ICanonical, ICanonicalSource } from '@darlean/canonical';
import { CanonicalFieldName, Class } from './valueobject';
import { NoInfer } from './utils';
import { IFromCanonicalOptions, IValueOptions, MethodKeys, Value, ValueClassLike } from './base';
export type UnknownFieldAction = 'ignore' | 'error';
export interface ISlotDef<TValue extends Value> {
    name: string;
    required: boolean;
    clazz: ValueClassLike<TValue>;
}
type StructMap = Map<CanonicalFieldName, Value & ICanonicalSource>;
export interface IStructValueOptions {
    unknownFieldAction?: UnknownFieldAction;
}
export declare function structvalue(logicalName?: string, options?: IStructValueOptions): (constructor: Function) => void;
export declare class StructDef {
    private _slots;
    private _requiredSlots;
    private _unknownFieldAction;
    constructor(parentDef?: StructDef);
    withRequiredField(name: CanonicalFieldName, def: ValueClassLike<Value>): StructDef;
    withOptionalField<TFieldValue extends Value>(name: CanonicalFieldName, def: ValueClassLike<TFieldValue>): StructDef;
    withUnknownFieldAction(action: UnknownFieldAction): this;
    getSlotDef<TSlotValue extends Value>(name: string): ISlotDef<TSlotValue> | undefined;
    getRequiredSlots(): string[];
    getSlots(): IterableIterator<ISlotDef<Value>>;
    get unknownFieldAction(): UnknownFieldAction;
}
export interface StructValueUnderscore {
    extractSlots(): StructMap;
    req<T>(name: CanonicalFieldName): T;
    opt<T>(name: CanonicalFieldName): T | undefined;
    checkSlots(): Map<CanonicalFieldName, Value>;
    get(slot: CanonicalFieldName): (Value & ICanonicalSource) | undefined;
    keys(): IterableIterator<CanonicalFieldName>;
    values(): IterableIterator<Value & ICanonicalSource>;
    entries(): IterableIterator<[CanonicalFieldName, Value & ICanonicalSource]>;
    get size(): number;
}
export declare class StructValue extends Value implements ICanonicalSource {
    private _slots?;
    private _canonical?;
    static required<T>(this: Class<T>): T;
    static optional<T>(this: Class<T>): T | undefined;
    /**
     * Creates a new struct value from a value that contains all of the fields of T. The fields
     * should be in the exact (native) casing as used in T. They are internally converted into the canonical field names.
     * Their values must be value objects (like StringValue or derived classes); not native types (like string).
     */
    static from<T extends StructValue, T2 = NoInfer<T>>(this: Class<T>, value: Omit<T2, keyof StructValue | MethodKeys<T2>>): T;
    /**
     * Creates a new struct value from a value that is a partial (subset of the fields) of T. The fields
     * should be in the exact casing as used in T. They are internally converted into the canonical field names.
     * Their values must be value objects (like StringValue or derived classes); not native types (like string).
     */
    static fromPartial<T extends StructValue, T2 = NoInfer<T>>(this: Class<T>, value: Partial<Omit<T2, keyof StructValue>>): T;
    /**
     * Creates a new struct value from a base value (of the same type) that is enricheded with a partial
     * (subset of the fields) of T. The fields should be in the exact casing as used in T. They are internally converted into
     * the canonical field names.
     * Their values must be value objects (like StringValue or derived classes); not native types (like string). Defined values
     * (that is, not having the value `undefined`) override the corresponding value in the output struct; values that are explicitly
     * undefined remove cause the corresponding key not to be present in the output struct.
     */
    static fromBase<T extends StructValue>(this: Class<T>, base: NoInfer<T>, value: Partial<Omit<NoInfer<T>, keyof StructValue>>): T;
    static fromCanonical<T extends StructValue>(this: Class<T>, value: ICanonical, options?: IFromCanonicalOptions): T;
    static fromSlots<T extends StructValue>(this: Class<T>, value: StructMap): T;
    /**
     * Creates a new struct value instance using the provided value. Regardless of whether the value is an ICanonical or
     * a Map, the field names must already be canonicalized. That also counts for field names of nested
     * values. When value is an object (`{..}`), the field names must *not* yet be canonicalized.
     * @param value
     */
    constructor(options: IValueOptions);
    _peekCanonicalRepresentation(): ICanonical<this>;
    get _(): StructValueUnderscore;
    equals(other: unknown): boolean;
    private _keys;
    private _values;
    private _entries;
    get _size(): number;
    get _logicalTypes(): string[];
    protected _deriveCanonicalRepresentation(): ICanonical;
    protected _get(slot: string): (Value & ICanonicalSource) | undefined;
    protected _fromCanonical(canonical: ICanonical, options?: IFromCanonicalOptions): StructMap;
    protected _toCanonical(value: StructMap, logicalTypes: string[]): ICanonical<this>;
    protected _validate(v: StructMap, fail: (msg: string) => void): StructMap | void;
    /**
     * Extracts the current slots and their values. Slot names are returned as canonicalized names.
     */
    private _extractSlots;
    private _req;
    private _opt;
    private _checkSlots;
}
export declare function ensureStructDefForConstructor(constructor: Function, extensions?: UnknownFieldAction): StructDef;
export declare function validateStrictFieldName(name: CanonicalFieldName): void;
export declare const structvalidation: (validator: (value: StructMap) => string | boolean | void, description?: string | undefined) => (constructor: Function) => void;
export {};
