tiny.smg.cli.subgraph
Defined in cli.
API (2)
Actions
Public operations.
Source
Source: tools/smg/src/cli/root.zig:9
zig
pub const subgraph = @import("subgraph.zig");Source: tools/smg/src/cli/subgraph.zig
zig
const std = @import("std");const smg = @import("../root.zig");const graph_mod = smg.graph;const model = smg.model;const table = smg.cli.table;const view = smg.view;pub fn writeSummary(allocator: std.mem.Allocator, writer: *std.Io.Writer, graph: graph_mod.Graph, name: []const u8, depth: i64, limit: i64) !void { const nodes = try view.allNodes(graph, allocator, null); const edges = try view.allEdges(graph, allocator); const degrees = try subgraphDegrees(allocator, graph); const displayed = if (limit <= 0 or @as(u64, @intCast(limit)) > @as(u64, @intCast(degrees.len))) degrees.len else @as(usize, @intCast(limit)); try writer.print("Subgraph of {s} (depth={d})\n", .{ name, depth }); try writer.print(" {d} nodes, {d} edges\n\n", .{ nodes.len, edges.len }); const columns = [_]table.Column{ .{ .header = "type", .max_width = 14 }, .{ .header = "name", .max_width = 56 }, .{ .header = "edges", .alignment = .right, .max_width = 8 }, }; var scratch_state = std.heap.ArenaAllocator.init(allocator); defer scratch_state.deinit(); const scratch = scratch_state.allocator(); var rows: std.ArrayList([]const []const u8) = .empty; for (degrees[0..displayed]) |row| { try table.appendRow(scratch, &rows, &.{ row.type, row.name, try std.fmt.allocPrint(scratch, "{d}", .{row.degree}), }); } try table.writeJsonOption(allocator, writer, &columns, rows.items, degrees.len, "--format json");}pub fn prune(allocator: std.mem.Allocator, graph: graph_mod.Graph, limit: usize) !graph_mod.Graph { const degrees = try subgraphDegrees(allocator, graph); var keep = std.StringHashMap(void).init(allocator); var out = graph_mod.init(allocator); const displayed = @min(limit, degrees.len); for (degrees[0..displayed]) |row| { try keep.put(row.name, {}); if (graph_mod.getNode(&graph, row.name)) |node| try graph_mod.addNode(&out, node); } for (try view.allEdges(graph, allocator)) |edge| { if (keep.contains(edge.source) and keep.contains(edge.target)) try graph_mod.addEdge(&out, edge); } return out;}const DegreeRow = struct { name: []const u8, type: []const u8, degree: usize,};fn subgraphDegrees(allocator: std.mem.Allocator, graph: graph_mod.Graph) ![]const DegreeRow { var rows: std.ArrayList(DegreeRow) = .empty; for (try view.allNodes(graph, allocator, null)) |node| { const incoming = try view.incoming(graph, allocator, node.name, null); const outgoing = try view.outgoing(graph, allocator, node.name, null); try rows.append(allocator, .{ .name = node.name, .type = node.type, .degree = incoming.len + outgoing.len }); } std.mem.sort(DegreeRow, rows.items, {}, degreeRowLess); return try rows.toOwnedSlice(allocator);}fn degreeRowLess(_: void, a: DegreeRow, b: DegreeRow) bool { if (a.degree != b.degree) return a.degree > b.degree; return std.mem.lessThan(u8, a.name, b.name);}test "subgraph summary renders degree ranked python shape" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const allocator = arena.allocator(); var graph = graph_mod.init(allocator); for ([_][]const u8{ "app", "app.main", "app.helper", "lib", "lib.util" }) |name| { try graph_mod.addNode(&graph, .{ .name = name, .type = if (std.mem.indexOfScalar(u8, name, '.')) |_| model.NodeType.function else model.NodeType.module }); } try graph_mod.addEdge(&graph, .{ .source = "app", .rel = model.RelType.contains, .target = "app.main" }); try graph_mod.addEdge(&graph, .{ .source = "app", .rel = model.RelType.contains, .target = "app.helper" }); try graph_mod.addEdge(&graph, .{ .source = "app.main", .rel = model.RelType.calls, .target = "app.helper" }); try graph_mod.addEdge(&graph, .{ .source = "app.helper", .rel = model.RelType.imports, .target = "lib.util" }); try graph_mod.addEdge(&graph, .{ .source = "lib", .rel = model.RelType.contains, .target = "lib.util" }); var out: std.Io.Writer.Allocating = .init(allocator); try writeSummary(allocator, &out.writer, graph, "app.helper", 2, 2); try std.testing.expectEqualStrings( "Subgraph of app.helper (depth=2)\n" ++ " 5 nodes, 5 edges\n" ++ "\n" ++ "type name edges\n" ++ "-------- ---------- -----\n" ++ "function app.helper 3\n" ++ "module app 2\n" ++ "(showing 2 of 5 \xE2\x80\x94 use --limit 0 for all, --format json for exact records)\n", out.written(), );}Audit
| Definitions | 3 |
|---|---|
| Public names | 3 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |