import { type U } from "../utils";
import { type Graph, type MutGraph } from ".";
/** an interface for hydrating serialized graph data */
export type Hydrator<T = unknown> = (parsed: unknown) => T;
/** convert graph to json */
export declare function toJson(grf: Graph): unknown;
/** the operator that defines hydration */
export interface JsonOps<out N = unknown, out L = unknown> {
    /** the node datum operator */
    nodeDatum: Hydrator<N>;
    /** the link datum operator */
    linkDatum: Hydrator<L>;
}
/**
 * an operator that hydrates serialized json into a graph
 *
 * Since type information is inherently lost with serialization, use {@link
 * nodeDatum} and {@link linkDatum} to define node and link data type, and
 * optionally perform extra deserialization.
 *
 * @typeParam NodeDatum - the node data type of the deserialized graph
 * @typeParam LinkDatum - the link data type of the deserialized graph
 * @typeParam Ops - the operators associated with deserialization
 */
export interface Json<NodeDatum, LinkDatum, Ops extends JsonOps<NodeDatum, LinkDatum>> {
    /**
     * deserialize parsed json as a graph
     *
     * @param json - the parsed json, usually created from `JSON.parse`
     * @returns graph - the deserialized graph
     */
    (json: unknown): MutGraph<NodeDatum, LinkDatum>;
    /**
     * set custom hydration for node data
     *
     * @example
     *
     * In the simpliest case, this can be used to cast the data types
     * appropriately (or alternatively you could just cast the Graph itself.
     *
     * ```ts
     * const grf: Graph<number> = ...
     * const builder = graphJson().nodeDatum(data => data as number);
     * const deser: MutGraph<number> = builder(JSON.parse(JSON.serialize(grf)));
     * ```
     *
     * @example
     *
     * Ideally though, you'll use typescripts warnings to make serialization
     * error proof:
     *
     * ```ts
     * const grf: Graph<number> = ...
     * const builder = graphJson().nodeDatum(data => {
     *   if (typeof data === "number") {
     *     return data;
     *   } else {
     *     throw new Error("...");
     *   }
     * });
     * const deser: MutGraph<number> = builder(JSON.parse(JSON.serialize(grf)));
     * ```
     */
    nodeDatum<NN, NewNode extends Hydrator<NN>>(val: NewNode & Hydrator<NN>): Json<NN, LinkDatum, U<Ops, "nodeDatum", NewNode>>;
    /** get the node data hydrator */
    nodeDatum(): Ops["nodeDatum"];
    /**
     * set custom hydration for link data
     *
     * See {@link nodeDatum} for example of what {@link Hydrator}s should look
     * like.
     */
    linkDatum<NL, NewLink extends Hydrator<NL>>(val: NewLink & Hydrator<NL>): Json<NodeDatum, NL, U<Ops, "linkDatum", NewLink>>;
    /** get the link data hydrator */
    linkDatum(): Ops["linkDatum"];
}
/**
 * the default {@link Json} operator created by {@link graphJson}
 *
 * This operator does no extra type conversion and so will result in unknown
 * data.
 */
export type DefaultJson = Json<unknown, unknown, JsonOps>;
/**
 * create a {@link Json} graph constructor with default settings
 *
 * If you serialize a graph or node using `JSON.stringify`, this operator can
 * be used to hydrate them back into a {@link MutGraph}. This is expecially
 * useful for serializing the graph to do layouts in a separate worker.
 *
 * If you serialize a {@link GraphNode} the deserialized graph will be the same
 * node that was serialized, but the rest of that node's connected component
 * will be deserialized as well, and still reachable via {@link Graph#nodes}.
 * The type information will inherently be lost, and will need to be cast.
 *
 * Since serialization doesn't inherently imply deserialization,
 * {@link Json#nodeDatum} and {@link Json#linkDatum} can be used to
 * provide custom hydration for node and linke data.
 *
 * @example
 *
 * This example shows how to deserialize a graph while losing type information.
 *
 * ```ts
 * const orig: Graph = ...
 * const serialized = JSON.stringify(orig);
 * const builder = graphJson();
 * const deserialized = builder(JSON.parse(serialized));
 * ```
 *
 * Note, that because no custom hydrators were given, `deserialized` will have
 * type `MutGraph<unknown, unknown>` which probably isn't desired.
 *
 * @example
 *
 * This example demonstrates using a simple data hydrator.
 *
 * ```ts
 * const orig: Graph<number, string> = ...
 * const serialized = JSON.stringify(orig);
 * const builder = graphJson()
 *     .nodeDatum(data => data as number)
 *     .linkDatum(data => data as string);
 * const deserialized = builder(JSON.parse(serialized));
 * ```
 *
 * Now `deserialized` has the same type as the original grah. In real use,
 * you'll probably want to use type guards to guarantee the data was
 * deserialized correctly.
 */
export declare function graphJson(...args: readonly never[]): DefaultJson;
