/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */
import type { PROTOTYPE_CONFIG_METHOD } from './LexicalConstants';
import type { AnyStaticNodeConfigValue, GetStaticNodeOwnConfig, GetStaticNodeType } from './LexicalNode';
import { type Klass, type LexicalNode, type LexicalNodeConfig, type LexicalUpdateJSON, NODE_STATE_KEY, type SerializedLexicalNode, type Spread } from '.';
/**
 * Read the state directly from the given object without `node.getLatest()`.
 * Safe to use outside of editor state context or to read a previous version,
 * equivalent to reading the property directly.
 */
export declare const NODE_STATE_DIRECT = "direct";
/**
 * Use `node.getLatest()` before reading the state, per the lexical convention
 * of only working with the latest version of a node.
 */
export declare const NODE_STATE_LATEST = "latest";
export type NodeStateVersion = typeof NODE_STATE_DIRECT | typeof NODE_STATE_LATEST;
/**
 * Get the value type (V) from a StateConfig
 */
export type StateConfigValue<S extends AnyStateConfig> = S extends StateConfig<infer _K, infer V> ? V : never;
/**
 * Get the key type (K) from a StateConfig
 */
export type StateConfigKey<S extends AnyStateConfig> = S extends StateConfig<infer K, infer _V> ? K : never;
/**
 * A value type, or an updater for that value type. For use with
 * {@link $setState} or any user-defined wrappers around it.
 */
export type ValueOrUpdater<V> = V | ((prevValue: V) => V);
/**
 * A type alias to make it easier to define setter methods on your node class
 *
 * @example
 * ```ts
 * const fooState = createState("foo", { parse: ... });
 * class MyClass extends TextNode {
 *   // ...
 *   setFoo(valueOrUpdater: StateValueOrUpdater<typeof fooState>): this {
 *     return $setState(this, fooState, valueOrUpdater);
 *   }
 * }
 * ```
 */
export type StateValueOrUpdater<Cfg extends AnyStateConfig> = ValueOrUpdater<StateConfigValue<Cfg>>;
export interface NodeStateConfig<S extends AnyStateConfig> {
    stateConfig: S;
    flat?: boolean;
}
export type RequiredNodeStateConfig = NodeStateConfig<AnyStateConfig> | AnyStateConfig;
export type StateConfigJSON<S> = S extends StateConfig<infer K, infer V> ? {
    [Key in K]?: V;
} : Record<never, never>;
export type RequiredNodeStateConfigJSON<Config extends RequiredNodeStateConfig, Flat extends boolean> = StateConfigJSON<Config extends NodeStateConfig<infer S> ? Spread<Config, {
    flat: false;
}> extends {
    flat: Flat;
} ? S : never : false extends Flat ? Config : never>;
export type Prettify<T> = {
    [K in keyof T]: T[K];
} & {};
export type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never;
export type CollectStateJSON<Tuple extends readonly RequiredNodeStateConfig[], Flat extends boolean> = UnionToIntersection<{
    [K in keyof Tuple]: RequiredNodeStateConfigJSON<Tuple[K], Flat>;
}[number]>;
type GetStaticNodeConfig<T extends LexicalNode> = [
    GetStaticNodeOwnConfig<T>
] extends [never] ? GetStaticNodeType<T> extends infer Type extends string ? string extends Type ? never : {
    [P in Type]: NonNullable<ReturnType<T[typeof PROTOTYPE_CONFIG_METHOD]>[P]>;
}[Type] extends infer Config extends AnyStaticNodeConfigValue ? Config & {
    readonly type: Type;
} : never : never : GetStaticNodeOwnConfig<T> extends infer Config extends AnyStaticNodeConfigValue ? Config & {
    readonly type: GetStaticNodeType<T>;
} : never;
type GetStaticNodeConfigs<T extends LexicalNode> = GetStaticNodeConfig<T> extends infer OwnConfig ? [
    OwnConfig
] extends [never] ? [] : OwnConfig extends {
    extends: Klass<infer Parent>;
} ? [GetStaticNodeConfig<Parent>] extends [never] ? [OwnConfig] : [OwnConfig, ...GetStaticNodeConfigs<Parent>] : [OwnConfig] : [];
type CollectStateConfigs<Configs> = Configs extends [
    infer OwnConfig,
    ...infer ParentConfigs
] ? OwnConfig extends {
    stateConfigs: infer StateConfigs;
} ? StateConfigs extends readonly RequiredNodeStateConfig[] ? [...StateConfigs, ...CollectStateConfigs<ParentConfigs>] : CollectStateConfigs<ParentConfigs> : CollectStateConfigs<ParentConfigs> : [];
export type GetNodeStateConfig<T extends LexicalNode> = CollectStateConfigs<GetStaticNodeConfigs<T>>;
/**
 * The NodeState JSON produced by this LexicalNode
 */
export type NodeStateJSON<T extends LexicalNode> = Prettify<{
    [NODE_STATE_KEY]?: Prettify<CollectStateJSON<GetNodeStateConfig<T>, false>>;
} & CollectStateJSON<GetNodeStateConfig<T>, true>>;
/**
 * Configure a value to be used with StateConfig.
 *
 * The value type should be inferred from the definition of parse.
 *
 * If the value type is not JSON serializable, then unparse must also be provided.
 *
 * Values should be treated as immutable, much like React.useState. Mutating
 * stored values directly will cause unpredictable behavior, is not supported,
 * and may trigger errors in the future.
 *
 * @example
 * ```ts
 * const numberOrNullState = createState('numberOrNull', {parse: (v) => typeof v === 'number' ? v : null});
 * //    ^? State<'numberOrNull', StateValueConfig<number | null>>
 * const numberState = createState('number', {parse: (v) => typeof v === 'number' ? v : 0});
 * //    ^? State<'number', StateValueConfig<number>>
 * ```
 *
 * Only the parse option is required, it is generally not useful to
 * override `unparse` or `isEqual`. However, if you are using
 * non-primitive types such as Array, Object, Date, or something
 * more exotic then you would want to override this. In these
 * cases you might want to reach for third party libraries.
 *
 * @example
 * ```ts
 * const isoDateState = createState('isoDate', {
 *   parse: (v): null | Date => {
 *     const date = typeof v === 'string' ? new Date(v) : null;
 *     return date && !isNaN(date.valueOf()) ? date : null;
 *   }
 *   isEqual: (a, b) => a === b || (a && b && a.valueOf() === b.valueOf()),
 *   unparse: (v) => v && v.toString()
 * });
 * ```
 *
 * You may find it easier to write a parse function using libraries like
 * zod, valibot, ajv, Effect, TypeBox, etc. perhaps with a wrapper function.
 */
export interface StateValueConfig<V> {
    /**
     * This function must return a default value when called with undefined,
     * otherwise it should parse the given JSON value to your type V. Note
     * that it is not required to copy or clone the given value, you can
     * pass it directly through if it matches the expected type.
     *
     * When you encounter an invalid value, it's up to you to decide
     * as to whether to ignore it and return the default value,
     * return some non-default error value, or throw an error.
     *
     * It is possible for V to include undefined, but if it does, then
     * it should also be considered the default value since undefined
     * can not be serialized to JSON so it is indistinguishable from the
     * default.
     *
     * Similarly, if your V is a function, then usage of {@link $setState}
     * must use an updater function because your type will be indistinguishable
     * from an updater function.
     */
    parse: (jsonValue: unknown) => V;
    /**
     * This is optional and for advanced use cases only.
     *
     * You may specify a function that converts V back to JSON.
     * This is mandatory when V is not a JSON serializable type.
     */
    unparse?: (parsed: V) => unknown;
    /**
     * This is optional and for advanced use cases only.
     *
     * Used to define the equality function so you can use an Array or Object
     * as V and still omit default values from the exported JSON.
     *
     * The default is `Object.is`, but something like `fast-deep-equal` might be
     * more appropriate for your use case.
     */
    isEqual?: (a: V, b: V) => boolean;
    /**
     * When a node is copied with {@link $copyNode} (not cloned), reset this
     * value to the default.
     */
    resetOnCopyNode?: boolean;
}
/**
 * The return value of {@link createState}, for use with
 * {@link $getState} and {@link $setState}.
 */
export declare class StateConfig<K extends string | symbol, V> {
    /** The string key used when serializing this state to JSON */
    readonly key: K;
    /** The parse function from the StateValueConfig passed to createState */
    readonly parse: (value?: unknown) => V;
    /**
     * The unparse function from the StateValueConfig passed to createState,
     * with a default that is simply a pass-through that assumes the value is
     * JSON serializable.
     */
    readonly unparse: (value: V) => unknown;
    /**
     * An equality function from the StateValueConfig, with a default of
     * Object.is.
     */
    readonly isEqual: (a: V, b: V) => boolean;
    /**
     * The result of `stateValueConfig.parse(undefined)`, which is computed only
     * once and used as the default value. When the current value `isEqual` to
     * the `defaultValue`, it will not be serialized to JSON.
     */
    readonly defaultValue: V;
    readonly resetOnCopyNode: boolean;
    constructor(key: K, stateValueConfig: StateValueConfig<V>);
}
/**
 * For advanced use cases, using this type is not recommended unless
 * it is required (due to TypeScript's lack of features like
 * higher-kinded types).
 *
 * A {@link StateConfig} type with any key and any value that can be
 * used in situations where the key and value type can not be known,
 * such as in a generic constraint when working with a collection of
 * StateConfig.
 *
 * {@link StateConfigKey} and {@link StateConfigValue} will be
 * useful when this is used as a generic constraint.
 */
export type AnyStateConfig = StateConfig<any, any>;
/**
 * Create a StateConfig for the given string key and StateValueConfig.
 *
 * The key must be locally unique. In dev you will get a key collision error
 * when you use two separate StateConfig on the same node with the same key.
 *
 * The returned StateConfig value should be used with {@link $getState} and
 * {@link $setState}.
 *
 * @param key The key to use
 * @param valueConfig Configuration for the value type
 * @returns a StateConfig
 *
 * @__NO_SIDE_EFFECTS__
 */
export declare function createState<K extends symbol | string, V>(key: K, valueConfig: StateValueConfig<V>): StateConfig<K, V>;
/**
 * The accessor for working with node state. This will read the value for the
 * state on the given node, and will return `stateConfig.defaultValue` if the
 * state has never been set on this node.
 *
 * The `version` parameter is optional and should generally be {@link NODE_STATE_LATEST},
 * consistent with the behavior of other node methods and functions,
 * but for certain use cases such as `updateDOM` you may have a need to
 * use {@link NODE_STATE_DIRECT} to read the state from a previous version of the node.
 *
 * For very advanced use cases, you can expect that {@link NODE_STATE_DIRECT} does not
 * require an editor state, just like directly accessing other properties
 * of a node without an accessor (e.g. `textNode.__text`).
 *
 * @param node Any LexicalNode
 * @param stateConfig The configuration of the state to read
 * @param version The default value {@link NODE_STATE_LATEST} will read the latest version of the node state, {@link NODE_STATE_DIRECT} will read the version that is stored on this LexicalNode which not reflect the version used in the current editor state
 * @returns The current value from the state, or the default value provided by the configuration.
 */
export declare function $getState<K extends string, V>(node: LexicalNode, stateConfig: StateConfig<K, V>, version?: NodeStateVersion): V;
/**
 * Given two versions of a node and a stateConfig, compare their state values
 * using `$getState(nodeVersion, stateConfig, NODE_STATE_DIRECT)`.
 * If the values are equal according to `stateConfig.isEqual`, return `null`,
 * otherwise return `[value, prevValue]`.
 *
 * This is useful for implementing updateDOM. Note that the `NODE_STATE_DIRECT`
 * version argument is used for both nodes.
 *
 * @param node Any LexicalNode
 * @param prevNode A previous version of node
 * @param stateConfig The configuration of the state to read
 * @returns `[value, prevValue]` if changed, otherwise `null`
 */
export declare function $getStateChange<T extends LexicalNode, K extends string, V>(node: T, prevNode: T, stateConfig: StateConfig<K, V>): null | [value: V, prevValue: V];
/**
 * Set the state defined by stateConfig on node. Like with `React.useState`
 * you may directly specify the value or use an updater function that will
 * be called with the previous value of the state on that node (which will
 * be the `stateConfig.defaultValue` if not set).
 *
 * When an updater function is used, the node will only be marked dirty if
 * `stateConfig.isEqual(prevValue, value)` is false.
 *
 * @example
 * ```ts
 * const toggle = createState('toggle', {parse: Boolean});
 * // set it direction
 * $setState(node, counterState, true);
 * // use an updater
 * $setState(node, counterState, (prev) => !prev);
 * ```
 *
 * @param node The LexicalNode to set the state on
 * @param stateConfig The configuration for this state
 * @param valueOrUpdater The value or updater function
 * @returns node
 */
export declare function $setState<Node extends LexicalNode, K extends string, V>(node: Node, stateConfig: StateConfig<K, V>, valueOrUpdater: ValueOrUpdater<V>): Node;
/**
 * @internal
 *
 * Opaque state to be stored on the editor's RegisterNode for use by NodeState
 */
export type SharedNodeState = {
    sharedConfigMap: SharedConfigMap;
    flatKeys: Set<string>;
};
/**
 * @internal
 *
 * Create the state to store on RegisteredNode
 */
export declare function createSharedNodeState(nodeConfig: LexicalNodeConfig): SharedNodeState;
type KnownStateMap = Map<AnyStateConfig, unknown>;
type UnknownStateRecord = Record<string, unknown>;
/**
 * @internal
 *
 * A Map of string keys to state configurations to be shared across nodes
 * and/or node versions.
 */
type SharedConfigMap = Map<string, AnyStateConfig>;
/**
 * @internal
 */
export declare class NodeState<T extends LexicalNode> {
    /**
     * @internal
     *
     * Track the (versioned) node that this NodeState was created for, to
     * facilitate copy-on-write for NodeState. When a LexicalNode is cloned,
     * it will *reference* the NodeState from its prevNode. From the nextNode
     * you can continue to read state without copying, but the first $setState
     * will trigger a copy of the prevNode's NodeState with the node property
     * updated.
     */
    readonly node: LexicalNode;
    /**
     * @internal
     *
     * State that has already been parsed in a get state, so it is safe. (can be returned with
     * just a cast since the proof was given before).
     *
     * Note that it uses StateConfig, so in addition to (1) the CURRENT VALUE, it has access to
     * (2) the State key (3) the DEFAULT VALUE and (4) the PARSE FUNCTION
     */
    readonly knownState: KnownStateMap;
    /**
     * @internal
     *
     * A copy of serializedNode[NODE_STATE_KEY] that is made when JSON is
     * imported but has not been parsed yet.
     *
     * It stays here until a get state requires us to parse it, and since we
     * then know the value is safe we move it to knownState.
     *
     * Note that since only string keys are used here, we can only allow this
     * state to pass-through on export or on the next version since there is
     * no known value configuration. This pass-through is to support scenarios
     * where multiple versions of the editor code are working in parallel so
     * an old version of your code doesnt erase metadata that was
     * set by a newer version of your code.
     */
    unknownState: undefined | UnknownStateRecord;
    /**
     * @internal
     *
     * This sharedNodeState is preserved across all instances of a given
     * node type in an editor and remains writable. It is how keys are resolved
     * to configuration.
     */
    readonly sharedNodeState: SharedNodeState;
    /**
     * @internal
     *
     * The count of known or unknown keys in this state, ignoring the
     * intersection between the two sets.
     */
    size: number;
    /**
     * @internal
     */
    constructor(node: T, sharedNodeState: SharedNodeState, unknownState?: undefined | UnknownStateRecord, knownState?: KnownStateMap, size?: number | undefined);
    /**
     * @internal
     *
     * Get the value from knownState, or parse it from unknownState
     * if it contains the given key.
     *
     * Updates the sharedConfigMap when no known state is found.
     * Updates unknownState and knownState when an unknownState is parsed.
     */
    getValue<K extends string, V>(stateConfig: StateConfig<K, V>): V;
    /**
     * @internal
     *
     * Used only for advanced use cases, such as collab. The intent here is to
     * allow you to diff states with a more stable interface than the properties
     * of this class.
     */
    getInternalState(): [
        {
            readonly [k in string]: unknown;
        } | undefined,
        ReadonlyMap<AnyStateConfig, unknown>
    ];
    /**
     * Encode this NodeState to JSON in the format that its node expects.
     * This returns `{[NODE_STATE_KEY]?: UnknownStateRecord}` rather than
     * `UnknownStateRecord | undefined` so that we can support flattening
     * specific entries in the future when nodes can declare what
     * their required StateConfigs are.
     */
    toJSON(): NodeStateJSON<T>;
    /**
     * @internal
     *
     * A NodeState is writable when the node to update matches
     * the node associated with the NodeState. This basically
     * mirrors how the EditorState NodeMap works, but in a
     * bottom-up organization rather than a top-down organization.
     *
     * This allows us to implement the same "copy on write"
     * pattern for state, without having the state version
     * update every time the node version changes (e.g. when
     * its parent or siblings change).
     *
     * @param node The node to associate with the state
     * @returns The next writable state
     */
    getWritable(node: T): NodeState<T>;
    /** @internal */
    resetOnCopyNode(): this;
    /** @internal */
    updateFromKnown<K extends string, V>(stateConfig: StateConfig<K, V>, value: V): void;
    /**
     * @internal
     *
     * This is intended for advanced use cases only, such
     * as collab or dev tools.
     *
     * Update a single key value pair from unknown state,
     * parsing it if the key is known to this node. This is
     * basically like updateFromJSON, but the effect is
     * isolated to a single entry.
     *
     * @param k The string key from an UnknownStateRecord
     * @param v The unknown value from an UnknownStateRecord
     */
    updateFromUnknown(k: string, v: unknown): void;
    /**
     * @internal
     *
     * Reset all existing state to default or empty values,
     * and perform any updates from the given unknownState.
     *
     * This is used when initializing a node's state from JSON,
     * or when resetting a node's state from JSON.
     *
     * @param unknownState The new state in serialized form
     */
    updateFromJSON(unknownState: undefined | UnknownStateRecord): void;
}
/**
 * @internal
 *
 * Only for direct use in very advanced integrations, such as lexical-yjs.
 * Typically you would only use {@link createState}, {@link $getState}, and
 * {@link $setState}. This is effectively the preamble for {@link $setState}.
 */
export declare function $getWritableNodeState<T extends LexicalNode>(node: T): NodeState<T>;
/**
 * @internal
 *
 * Get the SharedNodeState for a node on this editor
 */
export declare function $getSharedNodeState<T extends LexicalNode>(node: T): SharedNodeState;
/**
 * @internal
 *
 * This is used to implement LexicalNode.updateFromJSON and is
 * not intended to be exported from the package.
 *
 * @param node any LexicalNode
 * @param unknownState undefined or a serialized State
 * @returns A writable version of node, with the state set.
 */
export declare function $updateStateFromJSON<T extends LexicalNode>(node: T, serialized: LexicalUpdateJSON<SerializedLexicalNode>): T;
/**
 * @internal
 *
 * Return true if the two nodes have equivalent NodeState, to be used
 * to determine when TextNode are being merged, not a lot of use cases
 * otherwise.
 */
export declare function nodeStatesAreEquivalent<T extends LexicalNode>(a: undefined | NodeState<T>, b: undefined | NodeState<T>): boolean;
/**
 * @internal
 *
 * Clones the NodeState for a given node. Handles aliasing if the state references the from node.
 */
export declare function $cloneNodeState<T extends LexicalNode>(from: T, to: T): undefined | NodeState<T>;
export {};
