Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 19 additions & 30 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ enum Commands {
#[arg(long)]
entry: Option<PathBuf>,

/// Output machine-readable JSON
#[arg(long)]
json: bool,

/// Max packages to show in diff output (-1 for all)
#[arg(long, default_value_t = report::DEFAULT_TOP, allow_hyphen_values = true)]
limit: i32,
Expand Down Expand Up @@ -233,9 +237,10 @@ fn run(command: Commands, no_color: bool, sc: report::StderrColor) -> Result<Exi
a,
b,
entry,
json,
limit,
quiet,
} => run_diff(a, b, entry, limit, quiet, color, sc).map(|()| ExitCode::SUCCESS),
} => run_diff(a, b, entry, json, limit, quiet, color, sc).map(|()| ExitCode::SUCCESS),

Commands::Packages(ref args) => run_packages(args, color, sc).map(|()| ExitCode::SUCCESS),

Expand Down Expand Up @@ -309,11 +314,7 @@ fn run_trace(args: TraceArgs, color: bool, sc: report::StderrColor) -> Result<Ex
return Err(Error::TargetIsEntryPoint("--chain".into()));
}
let report = session.chain_report(chain_arg, args.include_dynamic);
if args.json {
println!("{}", report.to_json());
} else {
print!("{}", report.to_terminal(color));
}
report::emit(args.json, || report.to_json(), || report.to_terminal(color));
if report.chains.is_empty() {
return Ok(ExitCode::FAILURE);
}
Expand All @@ -327,11 +328,7 @@ fn run_trace(args: TraceArgs, color: bool, sc: report::StderrColor) -> Result<Ex
return Err(Error::TargetIsEntryPoint("--cut".into()));
}
let report = session.cut_report(cut_arg, args.top, args.include_dynamic);
if args.json {
println!("{}", report.to_json());
} else {
print!("{}", report.to_terminal(color));
}
report::emit(args.json, || report.to_json(), || report.to_terminal(color));
if report.chain_count == 0 {
return Ok(ExitCode::FAILURE);
}
Expand All @@ -343,11 +340,7 @@ fn run_trace(args: TraceArgs, color: bool, sc: report::StderrColor) -> Result<Ex
let saved = load_snapshot(snapshot_path)?;
let diff = query::diff_snapshots(&saved, &result.to_snapshot(&entry_rel));
let report = report::DiffReport::from_diff(&diff, &saved.entry, &entry_rel, args.limit);
if args.json {
println!("{}", report.to_json());
} else {
print!("{}", report.to_terminal(color));
}
report::emit(args.json, || report.to_json(), || report.to_terminal(color));
return Ok(ExitCode::SUCCESS);
}

Expand All @@ -361,6 +354,7 @@ fn run_trace(args: TraceArgs, color: bool, sc: report::StderrColor) -> Result<Ex
&opts,
args.no_cache,
args.limit,
args.json,
color,
sc,
)?;
Expand All @@ -369,11 +363,7 @@ fn run_trace(args: TraceArgs, color: bool, sc: report::StderrColor) -> Result<Ex

// Normal trace output
let report = session.trace_report(&opts, args.top_modules);
if args.json {
println!("{}", report.to_json());
} else {
print!("{}", report.to_terminal(color));
}
report::emit(args.json, || report.to_json(), || report.to_terminal(color));

if let Some(threshold) = args.max_weight.filter(|&t| report.static_weight_bytes > t) {
let kind = if args.include_dynamic {
Expand Down Expand Up @@ -410,6 +400,7 @@ fn handle_trace_diff(
opts: &query::TraceOptions,
no_cache: bool,
limit: i32,
json: bool,
color: bool,
sc: report::StderrColor,
) -> Result<(), Error> {
Expand Down Expand Up @@ -438,7 +429,7 @@ fn handle_trace_diff(
let diff_output = query::diff_snapshots(&result.to_snapshot(entry_rel), &diff_snapshot);
let report =
report::DiffReport::from_diff(&diff_output, entry_rel, &diff_snapshot.entry, limit);
print!("{}", report.to_terminal(color));
report::emit(json, || report.to_json(), || report.to_terminal(color));
Ok(())
}

Expand Down Expand Up @@ -470,11 +461,7 @@ fn run_packages(args: &PackagesArgs, color: bool, sc: report::StderrColor) -> Re
}

let report = session.packages_report(args.top);
if args.json {
println!("{}", report.to_json());
} else {
print!("{}", report.to_terminal(color));
}
report::emit(args.json, || report.to_json(), || report.to_terminal(color));
Ok(())
}

Expand Down Expand Up @@ -526,6 +513,7 @@ fn run_diff(
a: String,
b: Option<String>,
entry: Option<PathBuf>,
json: bool,
limit: i32,
quiet: bool,
color: bool,
Expand Down Expand Up @@ -568,13 +556,13 @@ fn run_diff(
let wt_snap = build_snapshot_from_working_tree(entry_path, quiet, sc)?;
let wt_label = wt_snap.entry.clone();
return finish_diff(
&snap_a, &label_a, &wt_snap, &wt_label, limit, color, start, quiet, sc,
&snap_a, &label_a, &wt_snap, &wt_label, json, limit, color, start, quiet, sc,
);
}
};

finish_diff(
&snap_a, &label_a, &snap_b, &label_b, limit, color, start, quiet, sc,
&snap_a, &label_a, &snap_b, &label_b, json, limit, color, start, quiet, sc,
)
}

Expand All @@ -584,6 +572,7 @@ fn finish_diff(
label_a: &str,
snap_b: &query::TraceSnapshot,
label_b: &str,
json: bool,
limit: i32,
color: bool,
start: Instant,
Expand All @@ -592,7 +581,7 @@ fn finish_diff(
) -> Result<(), Error> {
let diff_output = query::diff_snapshots(snap_a, snap_b);
let report = report::DiffReport::from_diff(&diff_output, label_a, label_b, limit);
print!("{}", report.to_terminal(color));
report::emit(json, || report.to_json(), || report.to_terminal(color));
if !quiet {
eprintln!(
"\n{} in {:.1}ms",
Expand Down
18 changes: 18 additions & 0 deletions src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,24 @@ pub struct PackageListEntry {
pub file_count: u32,
}

// ---------------------------------------------------------------------------
// Emit helper — centralizes --json dispatch
// ---------------------------------------------------------------------------

/// Emit a report to stdout, choosing JSON or terminal format.
///
/// Centralizes the `--json` / terminal dispatch so every CLI output path
/// goes through a single function. New output paths that forget the json
/// flag will be caught in code review: the pattern is always
/// `report::emit(json, ...)` rather than ad-hoc if/else.
pub fn emit(json: bool, json_fn: impl FnOnce() -> String, terminal_fn: impl FnOnce() -> String) {
if json {
println!("{}", json_fn());
} else {
print!("{}", terminal_fn());
}
}

// ---------------------------------------------------------------------------
// Report rendering
// ---------------------------------------------------------------------------
Expand Down
51 changes: 51 additions & 0 deletions tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,57 @@ fn unsupported_file_type() {
.stderr(predicate::str::contains("unsupported file type"));
}

// --- diff --json ---

#[test]
fn trace_diff_json() {
let p = common::TestProject::new();
let output = chainsaw()
.args(["trace", "--diff"])
.arg(p.root().join("b.ts"))
.args(["--json", "--no-cache"])
.arg(&p.entry)
.output()
.unwrap();
assert!(output.status.success());
let v: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert!(v["weight_delta"].is_number());
assert!(v["entry_a"].is_string());
assert!(v["entry_b"].is_string());
}

#[test]
fn diff_snapshot_json() {
let p = common::TestProject::new();
// Save two snapshots from different entry points.
let snap_a = p.root().join("snap_a.json");
let snap_b = p.root().join("snap_b.json");
chainsaw()
.args(["trace", "--save", snap_a.to_str().unwrap(), "--no-cache"])
.arg(&p.entry)
.assert()
.success();
chainsaw()
.args(["trace", "--save", snap_b.to_str().unwrap(), "--no-cache"])
.arg(p.root().join("b.ts"))
.assert()
.success();
// diff subcommand with --json
let output = chainsaw()
.args([
"diff",
snap_a.to_str().unwrap(),
snap_b.to_str().unwrap(),
"--json",
])
.output()
.unwrap();
assert!(output.status.success());
let v: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert!(v["weight_delta"].is_number());
assert!(v["entry_a"].is_string());
}

// --- quiet flag ---

#[test]
Expand Down