A directed and undirected multi-graph library with comprehensive graph algorithms
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Complete graph serialization and deserialization functionality for persistence, network transfer, and interoperability with other systems.
Converts graph instances to JSON-serializable objects preserving all graph data and metadata.
/**
* Converts graph to JSON-serializable object
* @param g - Graph instance to serialize
* @returns Object containing complete graph representation
*/
function write(g: Graph): SerializedGraph;
interface SerializedGraph {
options: {
directed: boolean;
multigraph: boolean;
compound: boolean;
};
nodes: SerializedNode[];
edges: SerializedEdge[];
value?: any; // Graph-level value if set
}
interface SerializedNode {
v: string; // Node ID
value?: any; // Node value/label if set
parent?: string; // Parent node ID (compound graphs only)
}
interface SerializedEdge {
v: string; // Source node ID
w: string; // Target node ID
name?: string; // Edge name (multigraphs only)
value?: any; // Edge value/label if set
}Usage Examples:
import { Graph, json } from "graphlib";
// Create and populate graph
const g = new Graph({ compound: true });
g.setGraph({ title: "Sample Graph", version: "1.0" });
// Add hierarchical nodes
g.setNode("group1", { type: "container" });
g.setNode("item1", { name: "First Item", data: 42 });
g.setNode("item2", { name: "Second Item", data: 73 });
g.setParent("item1", "group1");
g.setParent("item2", "group1");
// Add edges with metadata
g.setEdge("item1", "item2", {
relationship: "depends_on",
strength: 0.8
});
// Serialize to JSON
const serialized = json.write(g);
console.log(JSON.stringify(serialized, null, 2));Output format:
{
"options": {
"directed": true,
"multigraph": false,
"compound": true
},
"nodes": [
{
"v": "group1",
"value": { "type": "container" }
},
{
"v": "item1",
"value": { "name": "First Item", "data": 42 },
"parent": "group1"
},
{
"v": "item2",
"value": { "name": "Second Item", "data": 73 },
"parent": "group1"
}
],
"edges": [
{
"v": "item1",
"w": "item2",
"value": { "relationship": "depends_on", "strength": 0.8 }
}
],
"value": { "title": "Sample Graph", "version": "1.0" }
}Creates graph instances from JSON objects, restoring all graph properties and data.
/**
* Creates graph from JSON object
* @param json - Serialized graph object (format from write())
* @returns New Graph instance with restored data
*/
function read(json: SerializedGraph): Graph;Usage Examples:
// Restore graph from JSON
const restoredGraph = json.read(serialized);
// Verify restoration
console.log(restoredGraph.isCompound()); // true
console.log(restoredGraph.graph()); // { title: "Sample Graph", version: "1.0" }
console.log(restoredGraph.nodes()); // ["group1", "item1", "item2"]
console.log(restoredGraph.parent("item1")); // "group1"
console.log(restoredGraph.edge("item1", "item2"));
// { relationship: "depends_on", strength: 0.8 }// Save graph to file/database
const saveGraph = (graph, filename) => {
const serialized = json.write(graph);
const jsonString = JSON.stringify(serialized, null, 2);
// Save jsonString to file or database
return jsonString;
};
// Load graph from file/database
const loadGraph = (jsonString) => {
const parsed = JSON.parse(jsonString);
return json.read(parsed);
};// Client-side: send graph to server
const sendGraphToServer = async (graph) => {
const payload = json.write(graph);
const response = await fetch('/api/graphs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
return response.json();
};
// Server-side: receive and process graph
const processReceivedGraph = (jsonPayload) => {
const graph = json.read(jsonPayload);
// Process graph...
const result = analyzeGraph(graph);
// Send result back
return json.write(result);
};// Create diff between graph versions
const createGraphDiff = (oldGraph, newGraph) => {
const oldSerialized = json.write(oldGraph);
const newSerialized = json.write(newGraph);
return {
old: oldSerialized,
new: newSerialized,
timestamp: Date.now()
};
};
// Apply updates to existing graph
const updateGraph = (currentGraph, updates) => {
// Serialize current state
let current = json.write(currentGraph);
// Apply node updates
updates.nodes?.forEach(nodeUpdate => {
const existingNode = current.nodes.find(n => n.v === nodeUpdate.v);
if (existingNode) {
Object.assign(existingNode, nodeUpdate);
} else {
current.nodes.push(nodeUpdate);
}
});
// Apply edge updates
updates.edges?.forEach(edgeUpdate => {
const existingEdge = current.edges.find(e =>
e.v === edgeUpdate.v && e.w === edgeUpdate.w && e.name === edgeUpdate.name
);
if (existingEdge) {
Object.assign(existingEdge, edgeUpdate);
} else {
current.edges.push(edgeUpdate);
}
});
return json.read(current);
};// Add version info to serialized graphs
const writeVersionedGraph = (graph, version = "1.0") => {
const serialized = json.write(graph);
return {
...serialized,
formatVersion: version,
timestamp: new Date().toISOString()
};
};
// Handle different format versions
const readVersionedGraph = (data) => {
const version = data.formatVersion || "1.0";
switch (version) {
case "1.0":
return json.read(data);
case "2.0":
// Handle newer format
return json.read(migrateFromV2(data));
default:
throw new Error(`Unsupported format version: ${version}`);
}
};// Convert to other graph formats
const convertToD3Format = (graph) => {
const serialized = json.write(graph);
const nodes = serialized.nodes.map(node => ({
id: node.v,
...node.value
}));
const links = serialized.edges.map(edge => ({
source: edge.v,
target: edge.w,
...edge.value
}));
return { nodes, links };
};
// Convert from DOT format (conceptual)
const convertFromDot = (dotString) => {
const parsed = parseDotString(dotString); // External parser
const serialized = {
options: {
directed: parsed.directed,
multigraph: false,
compound: false
},
nodes: parsed.nodes.map(n => ({ v: n.id, value: n.attributes })),
edges: parsed.edges.map(e => ({
v: e.from,
w: e.to,
value: e.attributes
}))
};
return json.read(serialized);
};// Serialize only specific node/edge properties
const writeMinimal = (graph) => {
const full = json.write(graph);
return {
...full,
nodes: full.nodes.map(node => ({
v: node.v,
// Only keep essential properties
value: node.value ? {
id: node.value.id,
type: node.value.type
} : undefined
})),
edges: full.edges.map(edge => ({
v: edge.v,
w: edge.w,
name: edge.name,
// Only keep weight property
value: edge.value?.weight
}))
};
};// Custom serialization with data transformation
const writeWithTransform = (graph, transformer) => {
const serialized = json.write(graph);
if (transformer.nodes) {
serialized.nodes = serialized.nodes.map(transformer.nodes);
}
if (transformer.edges) {
serialized.edges = serialized.edges.map(transformer.edges);
}
if (transformer.graph && serialized.value) {
serialized.value = transformer.graph(serialized.value);
}
return serialized;
};
// Usage
const compressed = writeWithTransform(graph, {
nodes: (node) => ({
v: node.v,
d: compressNodeData(node.value) // Custom compression
}),
edges: (edge) => ({
v: edge.v,
w: edge.w,
w: compressEdgeWeight(edge.value) // Custom compression
})
});write() time complexity: O(V + E) where V = nodes, E = edgesread() time complexity: O(V + E)// For large graphs, consider chunked processing
const writeChunked = (graph, chunkSize = 1000) => {
const serialized = json.write(graph);
const chunks = [];
const nodes = serialized.nodes;
const edges = serialized.edges;
for (let i = 0; i < nodes.length; i += chunkSize) {
chunks.push({
type: 'nodes',
data: nodes.slice(i, i + chunkSize)
});
}
for (let i = 0; i < edges.length; i += chunkSize) {
chunks.push({
type: 'edges',
data: edges.slice(i, i + chunkSize)
});
}
return {
options: serialized.options,
value: serialized.value,
chunks
};
};JSON serialization errors are generally related to data types:
// Safe serialization with error handling
const safeWrite = (graph) => {
try {
const serialized = json.write(graph);
JSON.stringify(serialized); // Test serializability
return serialized;
} catch (error) {
console.error("Serialization failed:", error);
// Return minimal serializable version
return {
options: {
directed: graph.isDirected(),
multigraph: graph.isMultigraph(),
compound: graph.isCompound()
},
nodes: graph.nodes().map(v => ({ v })),
edges: graph.edges().map(e => ({ v: e.v, w: e.w, name: e.name }))
};
}
};