UNPKG

d3-dag

Version:

Layout algorithms for visualizing directed acylic graphs.

140 lines (139 loc) 5.08 kB
import { Graph, MutGraph } from "."; import { U } from "../utils"; /** an interface for hydrating serialized graph data */ export interface Hydrator<T = unknown> { /** * hydrate unknown parsed data into the desired type * * @param parsed - the parsed data without compile-time type information * @returns data - the verified and potentially parsed data */ (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;