Skip to documentation
SLOP

tiny.smg.command.query

Reference tiny.smg command query

Defined in command.

API (1)

Actions

Public operations.

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

Source

Called byCallsNo direct callersprivate; no linktools.smg.src.command.queryoutputEdgesprivate; no linktools.smg.src.command.querypathprivate; no linktools.smg.src.command.querysubgraphtext.listcontainsStringviewincomingviewoutgoingcommand.queryrun
Static calls · unresolved targets: 0 · external targets: 12.

Source: tools/smg/src/command/query.zig

zig
const std = @import("std");const smg = @import("../root.zig");const exports = smg.exports;const model = smg.model;const query_mod = smg.query;const text = smg.text;const view = smg.view;const cli_graph = smg.cli.graph;const cli_json = smg.cli.json;const cli_options = smg.cli.options;const cli_output = smg.cli.output;const cli_resolve = smg.cli.resolve;const cli_session = smg.command.session;const cli_subgraph = smg.cli.subgraph;const cli_table = smg.cli.table;const cli_validation = smg.cli.validation;pub fn run(allocator: std.mem.Allocator, phases: std.mem.Allocator, args: []const []const u8, limits: smg.Limits, boundary: cli_session.PhaseBoundary) !u8 {    const kind = args[0];    const rest = args[1..];    if (!text.list.containsString(&.{ "deps", "callers", "path", "subgraph", "incoming", "outgoing" }, kind)) {        try cli_output.writeClickUsageError(allocator, "query", "[OPTIONS] COMMAND [ARGS]...", try std.fmt.allocPrint(allocator, "No such command '{s}'.", .{kind}));        return 2;    }    if (std.mem.eql(u8, kind, "deps")) {        if (try cli_validation.validateQueryNameCommand(allocator, "query deps", "[OPTIONS] NAME", rest, &.{ "--depth", "--format", "--limit" }, &.{ "text", "json", "mermaid", "dot" })) return 2;        const pos = try cli_options.positional(allocator, rest);        const loaded = try cli_session.loadRead(allocator, phases, limits, boundary);        defer boundary.beginTeardown();        const graph = loaded[1];        const name = try cli_resolve.graphNode(allocator, graph, pos[0], limits.suggestions);        const names = try query_mod.transitiveDeps(allocator, graph, name, cli_options.depthValue(rest));        return try cli_graph.writeNames(allocator, graph, name, names, try std.fmt.allocPrint(allocator, "Dependencies of {s}", .{name}), cli_options.flagValue(rest, "--format") orelse "text", cli_options.signedLimitValue(rest));    }    if (std.mem.eql(u8, kind, "callers")) {        if (try cli_validation.validateQueryNameCommand(allocator, "query callers", "[OPTIONS] NAME", rest, &.{ "--depth", "--format", "--limit" }, &.{ "text", "json", "mermaid", "dot" })) return 2;        const pos = try cli_options.positional(allocator, rest);        const loaded = try cli_session.loadRead(allocator, phases, limits, boundary);        defer boundary.beginTeardown();        const graph = loaded[1];        const name = try cli_resolve.graphNode(allocator, graph, pos[0], limits.suggestions);        const names = try query_mod.transitiveCallers(allocator, graph, name, cli_options.depthValue(rest));        return try cli_graph.writeNames(allocator, graph, name, names, try std.fmt.allocPrint(allocator, "Callers of {s}", .{name}), cli_options.flagValue(rest, "--format") orelse "text", cli_options.signedLimitValue(rest));    }    if (std.mem.eql(u8, kind, "path")) return try path(allocator, phases, rest, limits, boundary);    if (std.mem.eql(u8, kind, "subgraph")) return try subgraph(allocator, phases, rest, limits, boundary);    if (std.mem.eql(u8, kind, "incoming")) {        if (try cli_validation.validateQueryNameCommand(allocator, "query incoming", "[OPTIONS] NAME", rest, &.{ "--rel", "--format", "--limit" }, &.{ "text", "json" })) return 2;        const pos = try cli_options.positional(allocator, rest);        const loaded = try cli_session.loadRead(allocator, phases, limits, boundary);        defer boundary.beginTeardown();        const graph = loaded[1];        const name = try cli_resolve.graphNode(allocator, graph, pos[0], limits.suggestions);        return try outputEdges(allocator, try view.incoming(graph, allocator, name, cli_options.flagValue(rest, "--rel")), cli_options.flagValue(rest, "--format") orelse "text", cli_options.signedLimitValue(rest));    }    if (std.mem.eql(u8, kind, "outgoing")) {        if (try cli_validation.validateQueryNameCommand(allocator, "query outgoing", "[OPTIONS] NAME", rest, &.{ "--rel", "--format", "--limit" }, &.{ "text", "json" })) return 2;        const pos = try cli_options.positional(allocator, rest);        const loaded = try cli_session.loadRead(allocator, phases, limits, boundary);        defer boundary.beginTeardown();        const graph = loaded[1];        const name = try cli_resolve.graphNode(allocator, graph, pos[0], limits.suggestions);        return try outputEdges(allocator, try view.outgoing(graph, allocator, name, cli_options.flagValue(rest, "--rel")), cli_options.flagValue(rest, "--format") orelse "text", cli_options.signedLimitValue(rest));    }    unreachable;}fn path(allocator: std.mem.Allocator, phases: std.mem.Allocator, args: []const []const u8, limits: smg.Limits, boundary: cli_session.PhaseBoundary) !u8 {    if (try cli_validation.rejectMissingOptionValues(allocator, args, &.{"--format"})) return 2;    if (try cli_validation.rejectUnexpectedOptionsPlain(allocator, "query path", "[OPTIONS] SOURCE TARGET", args, &.{"--format"})) return 2;    if (try cli_validation.rejectInvalidChoiceOption(allocator, "query path", "[OPTIONS] SOURCE TARGET", args, "--format", &.{ "text", "json" })) return 2;    const pos = try cli_options.positional(allocator, args);    if (pos.len == 0) {        try cli_output.writeClickUsageError(allocator, "query path", "[OPTIONS] SOURCE TARGET", "Missing argument 'SOURCE'.");        return 2;    }    if (pos.len == 1) {        try cli_output.writeClickUsageError(allocator, "query path", "[OPTIONS] SOURCE TARGET", "Missing argument 'TARGET'.");        return 2;    }    if (pos.len > 2) {        try cli_output.writeClickUsageError(allocator, "query path", "[OPTIONS] SOURCE TARGET", try cli_validation.unexpectedArgumentMessage(allocator, pos[2..]));        return 2;    }    const loaded = try cli_session.loadRead(allocator, phases, limits, boundary);    defer boundary.beginTeardown();    const graph = loaded[1];    const source = try cli_resolve.graphNode(allocator, graph, pos[0], limits.suggestions);    const target = try cli_resolve.graphNode(allocator, graph, pos[1], limits.suggestions);    const found_path = (try query_mod.shortestPath(allocator, graph, source, target)) orelse {        try cli_output.writeErrFmt(allocator, "Error: no path from {s} to {s}\n", .{ source, target });        return 1;    };    if (std.mem.eql(u8, cli_options.flagValue(args, "--format") orelse "", "json")) return try cli_json.stringArray(allocator, found_path);    var out: std.Io.Writer.Allocating = .init(allocator);    try writePathText(&out.writer, found_path);    return try cli_output.writeOut(out.written());}fn subgraph(allocator: std.mem.Allocator, phases: std.mem.Allocator, args: []const []const u8, limits: smg.Limits, boundary: cli_session.PhaseBoundary) !u8 {    if (try cli_validation.rejectMissingOptionValues(allocator, args, &.{ "--depth", "--format", "--limit" })) return 2;    if (try cli_validation.rejectUnexpectedOptionsPlain(allocator, "query subgraph", "[OPTIONS] NAME", args, &.{ "--depth", "--format", "--full", "--limit" })) return 2;    if (try cli_validation.rejectInvalidChoiceOption(allocator, "query subgraph", "[OPTIONS] NAME", args, "--format", &.{ "text", "json", "mermaid", "dot" })) return 2;    if (try cli_validation.rejectInvalidIntegerOption(allocator, "query subgraph", "[OPTIONS] NAME", args, "--depth")) return 2;    if (try cli_validation.rejectInvalidIntegerOption(allocator, "query subgraph", "[OPTIONS] NAME", args, "--limit")) return 2;    const pos = try cli_options.positional(allocator, args);    if (pos.len == 0) {        try cli_output.writeClickUsageError(allocator, "query subgraph", "[OPTIONS] NAME", "Missing argument 'NAME'.");        return 2;    }    if (pos.len > 1) {        try cli_output.writeClickUsageError(allocator, "query subgraph", "[OPTIONS] NAME", try cli_validation.unexpectedArgumentMessage(allocator, pos[1..]));        return 2;    }    const loaded = try cli_session.loadRead(allocator, phases, limits, boundary);    defer boundary.beginTeardown();    const graph = loaded[1];    const name = try cli_resolve.graphNode(allocator, graph, pos[0], limits.suggestions);    const depth = cli_options.signedOptionValue(args, "--depth", 2);    const sub = try query_mod.subgraph(allocator, graph, name, cli_options.unsignedTraversalDepth(depth), false);    const fmt = cli_options.flagValue(args, "--format") orelse "text";    if (!std.mem.eql(u8, fmt, "text")) return try cli_graph.write(allocator, sub, fmt);    if (cli_options.hasFlag(args, "--full")) {        const cap = if (cli_options.flagValue(args, "--limit")) |_| cli_options.signedLimitValue(args) else @as(i64, 50);        if (cap > 0 and sub.nodes.items.len > @as(usize, @intCast(cap))) {            const pruned = try cli_subgraph.prune(allocator, sub, @intCast(cap));            var out: std.Io.Writer.Allocating = .init(allocator);            try out.writer.writeAll(try exports.toText(allocator, pruned));            try out.writer.print("(showing {d} of {d} nodes -- use --limit 0 for all)\n", .{ cap, sub.nodes.items.len });            return try cli_output.writeOut(out.written());        }        return try cli_graph.write(allocator, sub, "text");    }    const limit = if (cli_options.flagValue(args, "--limit")) |_| cli_options.signedLimitValue(args) else @as(i64, 10);    var out: std.Io.Writer.Allocating = .init(allocator);    try cli_subgraph.writeSummary(allocator, &out.writer, sub, name, depth, limit);    return try cli_output.writeOut(out.written());}fn outputEdges(allocator: std.mem.Allocator, edges: []const model.Edge, fmt: []const u8, limit: i64) !u8 {    if (std.mem.eql(u8, fmt, "json")) return try cli_json.edgeArray(allocator, edges);    var out: std.Io.Writer.Allocating = .init(allocator);    try writeEdgesText(allocator, &out.writer, edges, limit);    return try cli_output.writeOut(out.written());}fn writePathText(writer: *std.Io.Writer, path_items: []const []const u8) !void {    for (path_items, 0..) |item, index| {        if (index != 0) try writer.writeAll(" -> ");        try writer.writeAll(item);    }    try writer.writeByte('\n');}fn writeEdgesText(allocator: std.mem.Allocator, writer: *std.Io.Writer, edges: []const model.Edge, limit: i64) !void {    if (edges.len == 0) {        try writer.writeAll("(none)\n");        return;    }    const displayed = cli_options.slicedLen(edges.len, limit);    const columns = [_]cli_table.Column{        .{ .header = "source", .max_width = 48 },        .{ .header = "rel", .max_width = 16 },        .{ .header = "target", .max_width = 48 },    };    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 (edges[0..displayed]) |edge| try cli_table.appendRow(scratch, &rows, &.{ edge.source, edge.rel, edge.target });    try cli_table.writeJsonOption(allocator, writer, &columns, rows.items, edges.len, "--format json");}test "query path text joins nodes with arrows" {    var out: std.Io.Writer.Allocating = .init(std.testing.allocator);    defer out.deinit();    try writePathText(&out.writer, &.{ "app.main", "app.helper", "lib.util" });    try std.testing.expectEqualStrings("app.main -> app.helper -> lib.util\n", out.written());}test "query edge text renders empty and limited tables" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    var empty: std.Io.Writer.Allocating = .init(allocator);    try writeEdgesText(allocator, &empty.writer, &.{}, 10);    try std.testing.expectEqualStrings("(none)\n", empty.written());    var out: std.Io.Writer.Allocating = .init(allocator);    try writeEdgesText(allocator, &out.writer, &.{        .{ .source = "app.main", .rel = model.RelType.calls, .target = "app.helper" },        .{ .source = "app.main", .rel = model.RelType.imports, .target = "lib.util" },    }, 1);    try std.testing.expect(std.mem.indexOf(u8, out.written(), "source") != null);    try std.testing.expect(std.mem.indexOf(u8, out.written(), "app.main") != null);    try std.testing.expect(std.mem.indexOf(u8, out.written(), "showing 1 of 2") != null);    try std.testing.expect(std.mem.indexOf(u8, out.written(), "--format json") != null);}

Source: tools/smg/src/command/root.zig:17

zig
pub const query = @import("query.zig");

Audit

Definitions2
Public names2
Members0
Version26.7.0
Revisiondaab053ee433