/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { FieldKindIdentifier, JsonableTree, ITreeCursor, ITreeCursorSynchronous, RevisionTag } from "../core";
import { FieldKind, Multiplicity, FieldChangeRebaser, FieldChangeHandler, NodeChangeset, FieldEditor } from "./modular-schema";
import { SequenceFieldEditor } from "./sequence-field";
/**
 * @alpha
 */
export declare type BrandedFieldKind<TName extends string, TMultiplicity extends Multiplicity, TEditor extends FieldEditor<any>> = FieldKind<TEditor, TMultiplicity> & {
    identifier: TName & FieldKindIdentifier;
};
/**
 * Picks the last value written.
 *
 * TODO: it seems impossible for this to obey the desired axioms.
 * Specifically inverse needs to cancel, restoring the value from the previous change which was discarded.
 */
export declare function lastWriteWinsRebaser<TChange>(data: {
    noop: TChange;
    invert: (changes: TChange) => TChange;
}): FieldChangeRebaser<TChange>;
export interface Replacement<T> {
    old: T;
    new: T;
}
export declare type ReplaceOp<T> = Replacement<T> | 0;
/**
 * Picks the last value written.
 *
 * Consistent if used on valid paths with correct old states.
 */
export declare function replaceRebaser<T>(): FieldChangeRebaser<ReplaceOp<T>>;
/**
 * ChangeHandler that only handles no-op / identity changes.
 */
export declare const noChangeHandler: FieldChangeHandler<0>;
/**
 * ChangeHandler that does not support any changes.
 *
 * TODO: Due to floating point precision compose is not quite associative.
 * This may violate our requirements.
 * This could be fixed by making this integer only
 * and handling values past Number.MAX_SAFE_INTEGER (ex: via an arbitrarily large integer library)
 * or via modular arithmetic.
 */
export declare const counterHandle: FieldChangeHandler<number>;
/**
 * Field kind for counters.
 * Stores a single value which corresponds to number which can be added to.
 *
 * This is an example of a few interesting things:
 *
 * - A field kind with some constraints on what can be under it type wise.
 * Other possible examples which would do this include sets, maps (for their keys),
 * or any domain specific specialized kinds.
 *
 * - A field kind with commutative edits.
 *
 * TODO:
 * What should the subtrees under this look like?
 * How does it prevent / interact with direct edits to the subtree (ex: set value)?
 * How should it use its type set?
 * How should it handle lack of associative addition due to precision and overflow?
 */
export declare const counter: BrandedFieldKind<"Counter", Multiplicity.Value, FieldEditor<number>>;
export declare type NodeUpdate = {
    set: JsonableTree;
    changes?: NodeChangeset;
} | {
    /**
     * The node being restored.
     */
    revert: ITreeCursorSynchronous;
    revision: RevisionTag | undefined;
    changes?: NodeChangeset;
};
export interface ValueChangeset {
    value?: NodeUpdate;
    changes?: NodeChangeset;
}
export interface ValueFieldEditor extends FieldEditor<ValueChangeset> {
    /**
     * Creates a change which replaces the current value of the field with `newValue`.
     */
    set(newValue: ITreeCursor): ValueChangeset;
}
/**
 * Exactly one item.
 */
export declare const value: BrandedFieldKind<"Value", Multiplicity.Value, ValueFieldEditor>;
export interface OptionalFieldChange {
    /**
     * The new content for the trait. If undefined, the trait will be cleared.
     */
    newContent?: NodeUpdate;
    /**
     * Whether the field was empty in the state this change is based on.
     */
    wasEmpty: boolean;
}
export interface OptionalChangeset {
    /**
     * If defined, specifies the new content for the field.
     */
    fieldChange?: OptionalFieldChange;
    /**
     * Changes to the node which were in the field before this changeset is applied, or the node deleted in this field in the given revision
     */
    childChange?: NodeChangeset;
    /**
     * The revision the node `childChange` is referring to was deleted in.
     * If undefined, `childChange` refers to the node currently in this field.
     *
     * This representation is sufficient for representing changes to the node present before this changeset and
     * after this changeset, but not for changes to nodes that existed only transiently in a transaction.
     */
    deletedBy?: RevisionTag;
}
export interface OptionalFieldEditor extends FieldEditor<OptionalChangeset> {
    /**
     * Creates a change which replaces the field with `newContent`
     * @param newContent - the new content for the field
     * @param wasEmpty - whether the field is empty when creating this change
     */
    set(newContent: ITreeCursor | undefined, wasEmpty: boolean): OptionalChangeset;
}
/**
 * 0 or 1 items.
 */
export declare const optional: BrandedFieldKind<"Optional", Multiplicity.Optional, OptionalFieldEditor>;
/**
 * 0 or more items.
 */
export declare const sequence: BrandedFieldKind<"Sequence", Multiplicity.Sequence, SequenceFieldEditor>;
/**
 * Exactly 0 items.
 *
 * Using Forbidden makes what types are listed for allowed in a field irrelevant
 * since the field will never have values in it.
 *
 * Using Forbidden is equivalent to picking a kind that permits empty (like sequence or optional)
 * and having no allowed types (or only never types).
 * Because of this, its possible to express everything constraint wise without Forbidden,
 * but using Forbidden can be more semantically clear than optional with no allowed types.
 *
 * For view schema, this can be useful if you need to:
 * - run a specific out of schema handler when a field is present,
 * but otherwise are ignoring or tolerating (ex: via extra fields) unmentioned fields.
 * - prevent a specific field from being used as an extra field
 * (perhaps for some past of future compatibility reason)
 * - keep a field in a schema for metadata purposes
 * (ex: for improved error messaging, error handling or documentation)
 * that is not used in this specific version of the schema (ex: to document what it was or will be used for).
 *
 * For stored schema, this can be useful if you need to:
 * - have a field which can have its schema updated to Optional or Sequence of any type.
 * - to exclude a field from extra fields
 * - for the schema system to use as a default for fields which aren't declared
 * (ex: when updating a field that did not exist into one that does)
 *
 * See {@link emptyField} for a constant, reusable field using Forbidden.
 */
export declare const forbidden: BrandedFieldKind<"Forbidden", Multiplicity.Forbidden, FieldEditor<0>>;
/**
 * Default field kinds by identifier
 */
export declare const fieldKinds: ReadonlyMap<FieldKindIdentifier, FieldKind>;
/**
 * @alpha
 */
export interface ValueFieldKind extends BrandedFieldKind<"Value", Multiplicity.Value, FieldEditor<any>> {
}
/**
 * @alpha
 */
export interface Optional extends BrandedFieldKind<"Optional", Multiplicity.Optional, FieldEditor<any>> {
}
/**
 * @alpha
 */
export interface Sequence extends BrandedFieldKind<"Sequence", Multiplicity.Sequence, FieldEditor<any>> {
}
/**
 * @alpha
 */
export interface Forbidden extends BrandedFieldKind<"Forbidden", Multiplicity.Forbidden, FieldEditor<any>> {
}
/**
 * Default FieldKinds with their editor types erased.
 * @alpha
 */
export declare const FieldKinds: {
    readonly value: ValueFieldKind;
    readonly optional: Optional;
    readonly sequence: Sequence;
    readonly forbidden: Forbidden;
};
/**
 * @alpha
 */
export declare type FieldKindTypes = typeof FieldKinds[keyof typeof FieldKinds];
//# sourceMappingURL=defaultFieldKinds.d.ts.map