tiny.smg.command.between
Defined in command.
API (3)
Actions
Public operations.
Source
Source: tools/smg/src/command/between.zig
zig
const std = @import("std");const smg = @import("../root.zig");const graph_mod = smg.graph;const model = smg.model;const query = smg.query;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_validation = smg.cli.validation;const view = smg.view;pub fn run(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, "between", "[OPTIONS] A B", args, &.{"--format"})) return 2; if (try cli_validation.rejectInvalidChoiceOption(allocator, "between", "[OPTIONS] A B", args, "--format", &.{ "text", "json" })) return 2; const pos = try cli_options.positional(allocator, args); if (pos.len == 0) { try cli_output.writeClickUsageError(allocator, "between", "[OPTIONS] A B", "Missing argument 'A'."); return 2; } if (pos.len == 1) { try cli_output.writeClickUsageError(allocator, "between", "[OPTIONS] A B", "Missing argument 'B'."); return 2; } if (pos.len > 2) { try cli_output.writeClickUsageError(allocator, "between", "[OPTIONS] A B", 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 path = try query.shortestPath(allocator, graph, source, target); const direct = try directEdges(allocator, graph, source, target); var out: std.Io.Writer.Allocating = .init(allocator); if (std.mem.eql(u8, cli_options.flagValue(args, "--format") orelse "", "json")) { try cli_json.writeBetween(&out.writer, source, target, path, direct); return try cli_output.writeOut(out.written()); } try writeText(allocator, &out.writer, source, target, path, direct); return try cli_output.writeOut(out.written());}pub fn directEdges(allocator: std.mem.Allocator, graph: graph_mod.Graph, source: []const u8, target: []const u8) ![]const model.Edge { var out: std.ArrayList(model.Edge) = .empty; for (try view.allEdges(graph, allocator)) |edge| { const forward = std.mem.eql(u8, edge.source, source) and std.mem.eql(u8, edge.target, target); const backward = std.mem.eql(u8, edge.source, target) and std.mem.eql(u8, edge.target, source); if (forward or backward) try out.append(allocator, edge); } return try out.toOwnedSlice(allocator);}pub fn writeText(allocator: std.mem.Allocator, writer: *std.Io.Writer, source: []const u8, target: []const u8, path: ?[]const []const u8, direct: []const model.Edge) !void { if (path) |items| { var line: std.Io.Writer.Allocating = .init(allocator); defer line.deinit(); try line.writer.writeAll("Path: "); for (items, 0..) |item, index| { if (index != 0) try line.writer.writeAll(" -> "); try line.writer.writeAll(item); } try writeWrappedPlainLine(writer, line.written(), 80); } else { try writer.print("No path between {s} and {s}\n", .{ source, target }); } if (direct.len != 0) { try writer.writeAll("\nDirect edges:\n"); for (direct) |edge| { var line: std.Io.Writer.Allocating = .init(allocator); defer line.deinit(); try line.writer.print(" {s} --{s}--> {s}", .{ edge.source, edge.rel, edge.target }); try writeWrappedPlainLine(writer, line.written(), 80); } }}fn writeWrappedPlainLine(writer: *std.Io.Writer, line: []const u8, width: usize) !void { var start: usize = 0; while (line.len - start > width) { var split = start + width; while (split > start and line[split] != ' ') split -= 1; if (split == start) { split = start + width; try writer.writeAll(line[start..split]); try writer.writeByte('\n'); start = split; } else { try writer.writeAll(line[start .. split + 1]); try writer.writeByte('\n'); start = split + 1; while (start < line.len and line[start] == ' ') start += 1; } } try writer.writeAll(line[start..]); try writer.writeByte('\n');}test "between renders python text contracts" { 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{ "a", "b", "c", "d", "app.api.handler", "app.service.Service", "app.service.Service.load", "app.db.query", "really.long.source.module.component.Handler", "really.long.target.module.component.ServiceMethod", }) |name| try graph_mod.addNode(&graph, .{ .name = name, .type = model.NodeType.module }); try graph_mod.addEdge(&graph, .{ .source = "a", .rel = model.RelType.calls, .target = "b" }); try graph_mod.addEdge(&graph, .{ .source = "b", .rel = model.RelType.imports, .target = "c" }); try graph_mod.addEdge(&graph, .{ .source = "app.api.handler", .rel = model.RelType.calls, .target = "app.service.Service" }); try graph_mod.addEdge(&graph, .{ .source = "app.service.Service", .rel = model.RelType.calls, .target = "app.service.Service.load" }); try graph_mod.addEdge(&graph, .{ .source = "app.service.Service.load", .rel = model.RelType.calls, .target = "app.db.query" }); try graph_mod.addEdge(&graph, .{ .source = "really.long.source.module.component.Handler", .rel = model.RelType.calls, .target = "really.long.target.module.component.ServiceMethod" }); const path = try query.shortestPath(allocator, graph, "a", "c"); const long_path = try query.shortestPath(allocator, graph, "app.api.handler", "app.db.query"); const long_direct = try directEdges(allocator, graph, "really.long.source.module.component.Handler", "really.long.target.module.component.ServiceMethod"); var out: std.Io.Writer.Allocating = .init(allocator); try writeText(allocator, &out.writer, "a", "c", path, &.{}); try writeText(allocator, &out.writer, "app.api.handler", "app.db.query", long_path, &.{}); try writeText(allocator, &out.writer, "really.long.source.module.component.Handler", "really.long.target.module.component.ServiceMethod", try query.shortestPath(allocator, graph, "really.long.source.module.component.Handler", "really.long.target.module.component.ServiceMethod"), long_direct); try std.testing.expectEqualStrings("Path: a -> b -> c\n" ++ "Path: app.api.handler -> app.service.Service -> app.service.Service.load -> \n" ++ "app.db.query\n" ++ "Path: really.long.source.module.component.Handler -> \n" ++ "really.long.target.module.component.ServiceMethod\n" ++ "\n" ++ "Direct edges:\n" ++ " really.long.source.module.component.Handler --calls--> \n" ++ "really.long.target.module.component.ServiceMethod\n", out.written());}Source: tools/smg/src/command/root.zig:4
zig
pub const between = @import("between.zig");Audit
| Definitions | 4 |
|---|---|
| Public names | 4 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |