Skip to documentation
SLOP

tiny.smg.cli.subgraph

Reference tiny.smg cli subgraph

Defined in cli.

API (2)

Actions

Public operations.

No direct callersNo direct callsclisubgraph
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callersprivate; no linktools.smg.src.cli.subgraphsubgraphDegreesviewallEdgescli.subgraphprune
Static calls · unresolved targets: 1 · external targets: 5.
Called byCallstest; no linktools.smg.src.cli.subgraphtest: subgraph summary renders degree...private sourcelib.markdown.src.tableappendRowprivate; no linktools.smg.src.cli.subgraphsubgraphDegreesviewallEdgesviewallNodescli.subgraphwriteSummary
Static calls · unresolved targets: 1 · external targets: 3.

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

Definitions3
Public names3
Members0
Version26.7.0
Revisiondaab053ee433