d3-dag
Version:
Layout algorithms for visualizing directed acylic graphs.
140 lines (139 loc) • 5.08 kB
TypeScript
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;