use serde_json::{json, Value};
use crate::{automation, error::HenError};
use super::{
artifacts::{request_failure_json, run_record_json},
common::{execution_trace_json, with_type},
json::{hen_diagnostic_json, hen_error_json, inspection_result_json},
BodyReportOptions,
};
pub fn run_outcome_ndjson(
outcome: &automation::RunOutcome,
body_options: BodyReportOptions,
) -> String {
let mut lines = vec![json!({
"type": "run",
"collection": {
"path": outcome.collection.path.display().to_string(),
"name": outcome.collection.name,
"description": outcome.collection.description,
"availableEnvironments": outcome.collection.available_environments,
"selectedEnvironment": outcome.collection.selected_environment,
},
"plan": outcome.plan,
"selectedRequests": outcome.selected_requests,
"primaryTarget": outcome.primary_target,
"executionFailed": outcome.execution_failed,
"interrupted": outcome.interrupted.is_some(),
"interruptSignal": outcome.interrupted.map(|signal| signal.as_str()),
"recordCount": outcome.records.len(),
"failureCount": outcome.failures.len(),
"traceCount": outcome.trace.len(),
})];
lines.extend(
outcome
.records
.iter()
.map(|record| with_type(run_record_json(record, body_options), "record")),
);
lines.extend(
outcome
.failures
.iter()
.map(|failure| with_type(request_failure_json(failure, body_options), "failure")),
);
lines.extend(
outcome
.trace
.iter()
.map(|entry| with_type(execution_trace_json(entry), "trace")),
);
render_ndjson(lines)
}
pub fn verification_result_ndjson(result: &automation::VerificationResult) -> String {
verification_diagnostics_result_ndjson(&automation::VerificationDiagnosticsResult {
ok: true,
path: result.path.clone(),
summary: Some(result.summary.clone()),
required_inputs: result.required_inputs.clone(),
diagnostics: Vec::new(),
error: None,
})
}
pub fn verification_diagnostics_result_ndjson(
result: &automation::VerificationDiagnosticsResult,
) -> String {
let mut lines = vec![json!({
"type": "verify",
"ok": result.ok,
"path": result.path.as_ref().map(|path| path.display().to_string()),
"name": result.summary.as_ref().map(|summary| summary.name.clone()),
"description": result.summary.as_ref().map(|summary| summary.description.clone()),
"availableEnvironments": result.summary.as_ref().map(|summary| summary.available_environments.clone()).unwrap_or_default(),
"requestCount": result.summary.as_ref().map(|summary| summary.requests.len()).unwrap_or(0),
"requiredInputCount": result.required_inputs.len(),
"diagnosticCount": result.diagnostics.len(),
})];
if let Some(summary) = result.summary.as_ref() {
lines.extend(summary.requests.iter().map(|request| {
json!({
"type": "request",
"index": request.index,
"description": request.description,
"method": request.method,
"url": request.url,
"protocol": request.protocol,
"protocolContext": request.protocol_context,
})
}));
}
lines.extend(result.required_inputs.iter().map(|prompt| {
json!({
"type": "requiredInput",
"name": prompt.name,
"default": prompt.default,
})
}));
lines.extend(
result
.diagnostics
.iter()
.map(|diagnostic| with_type(hen_diagnostic_json(diagnostic), "diagnostic")),
);
render_ndjson(lines)
}
pub fn inspection_result_ndjson(result: &automation::InspectionResult) -> String {
render_ndjson(vec![with_type(inspection_result_json(result), "inspect")])
}
pub fn hen_error_ndjson(error: &HenError) -> String {
render_ndjson(vec![with_type(hen_error_json(error), "error")])
}
fn render_ndjson(lines: Vec<Value>) -> String {
lines
.into_iter()
.map(|line| serde_json::to_string(&line).expect("ndjson line should serialize"))
.collect::<Vec<_>>()
.join("\n")
}