// serializer.el — Export graph as SVG string or portable JSON. // // Public API: // graph_to_svg(graph_json, width, height) -> String // graph_json: { "nodes": [...], "edges": [...] } // Full pipeline: parse -> layout -> render -> SVG string. // // graph_to_json(nodes_json, edges_json, positions_json) -> String // Portable export combining node data with computed positions. // Useful for saving layouts to disk or sending to other tools. // ── graph_to_svg ────────────────────────────────────────────────────────────── // // Convenience wrapper: accepts a combined graph JSON object and returns SVG. fn graph_to_svg(graph_json: String, width: Int, height: Int) -> String { let nodes_raw: String = json_get_raw(graph_json, "nodes") let edges_raw: String = json_get_raw(graph_json, "edges") let nodes_json: String = if str_eq(nodes_raw, "") { "[]" } else { nodes_raw } let edges_json: String = if str_eq(edges_raw, "") { "[]" } else { edges_raw } graph_svg_endpoint(nodes_json, edges_json, width, height) } // ── graph_to_json ───────────────────────────────────────────────────────────── // // Merge node metadata with computed positions into a portable export format. // Output: { "nodes": [{...node fields..., "x": 123.0, "y": 456.0}], "edges": [...] } fn graph_to_json(nodes_json: String, edges_json: String, positions_json: String) -> String { // Index positions by id build_position_index(positions_json) let node_count: Int = json_array_len(nodes_json) let nodes_out: String = "[" let i: Int = 0 while i < node_count { let n: String = json_array_get(nodes_json, i) let id: String = json_get_string(n, "id") let x: Float = get_pos_x(id) let y: Float = get_pos_y(id) // Inject x/y into the node JSON let n_with_pos: String = json_set(json_set(n, "x", format_float(x, 1)), "y", format_float(y, 1)) if i == 0 { let nodes_out = nodes_out + n_with_pos } else { let nodes_out = nodes_out + "," + n_with_pos } let i = i + 1 } let nodes_out = nodes_out + "]" "{\"nodes\":" + nodes_out + ",\"edges\":" + edges_json + "}" } // ── graph_snapshot_svg ──────────────────────────────────────────────────────── // // Render a snapshot of the current in-process Engram graph as SVG. // Uses engram_scan_nodes_json and reads edges from the snapshot file. // This is the function called by the CGI Studio /api/graph/svg endpoint. fn graph_snapshot_svg(width: Int, height: Int, snap_path: String) -> String { let nodes_json: String = engram_scan_nodes_json(9999, 0) let n_count: Int = json_array_len(nodes_json) // Read edges from snapshot file let snap: String = fs_read(snap_path) let edges_raw: String = if str_eq(snap, "") { "[]" } else { json_get_raw(snap, "edges") } let edges_json: String = if str_eq(edges_raw, "") { "[]" } else { edges_raw } if n_count == 0 { // Return an empty SVG with a "no data" message return svg_open(width, height) + "No nodes in graph" + svg_close() } graph_svg_endpoint(nodes_json, edges_json, width, height) }