use serde_json::{json, Value};
use crate::{
automation::{self, PromptRequirement},
error::{
HenDiagnostic, HenDiagnosticLocation, HenDiagnosticPosition,
HenDiagnosticRange, HenDiagnosticRelatedInformation,
HenDiagnosticSuggestion, HenDiagnosticSymbol, HenError,
},
};
use super::{
artifacts::{request_failure_json, run_record_json},
common::execution_trace_json,
redaction::OutputRedactor,
BodyReportOptions,
};
pub fn run_outcome_json(
outcome: &automation::RunOutcome,
body_options: BodyReportOptions,
) -> Value {
json!({
"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,
"requiredInputs": outcome.collection.required_inputs.iter().map(prompt_requirement_json).collect::<Vec<_>>(),
"requests": outcome.collection.requests.iter().map(|request| {
let redactor = OutputRedactor::new(&request.sensitive_values);
json!({
"index": request.index,
"description": redactor.redact_text(&request.description),
"method": request.method,
"url": redactor.redact_text(&request.url),
"protocol": request.protocol,
"protocolContext": request.protocol_context.as_ref().map(|value| redactor.redact_json_value(value)),
"dependencies": request.dependencies.iter().map(|dependency| redactor.redact_text(dependency)).collect::<Vec<_>>(),
})
}).collect::<Vec<_>>()
},
"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()),
"records": outcome.records.iter().map(|record| run_record_json(record, body_options)).collect::<Vec<_>>(),
"failures": outcome.failures.iter().map(|failure| request_failure_json(failure, body_options)).collect::<Vec<_>>(),
"trace": outcome.trace.iter().map(execution_trace_json).collect::<Vec<_>>(),
})
}
pub fn verification_result_json(result: &automation::VerificationResult) -> Value {
verification_diagnostics_result_json(&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_json(
result: &automation::VerificationDiagnosticsResult,
) -> Value {
let mut root = serde_json::Map::new();
root.insert("ok".to_string(), json!(result.ok));
root.insert(
"path".to_string(),
json!(result.path.as_ref().map(|path| path.display().to_string())),
);
root.insert(
"summary".to_string(),
result.summary.as_ref().map_or(Value::Null, syntax_summary_json),
);
root.insert(
"requiredInputs".to_string(),
Value::Array(
result
.required_inputs
.iter()
.map(prompt_requirement_json)
.collect(),
),
);
root.insert(
"diagnostics".to_string(),
Value::Array(result.diagnostics.iter().map(hen_diagnostic_json).collect()),
);
if let Some(summary) = result.summary.as_ref() {
root.insert("name".to_string(), json!(summary.name));
root.insert("description".to_string(), json!(summary.description));
root.insert(
"availableEnvironments".to_string(),
json!(summary.available_environments),
);
root.insert(
"requests".to_string(),
Value::Array(summary.requests.iter().map(syntax_request_summary_json).collect()),
);
}
if let Some(error) = result.error.as_ref() {
root.insert("error".to_string(), verification_legacy_error_json(error));
}
Value::Object(root)
}
pub fn inspection_result_json(result: &automation::InspectionResult) -> Value {
json!({
"path": result.path.as_ref().map(|path| path.display().to_string()),
"name": result.summary.summary.name,
"description": result.summary.summary.description,
"availableEnvironments": result.summary.summary.available_environments,
"requiredInputs": result.required_inputs.iter().map(prompt_requirement_json).collect::<Vec<_>>(),
"summary": syntax_summary_json(&result.summary.summary),
"declarations": result.summary.declarations.iter().map(syntax_declaration_summary_json).collect::<Vec<_>>(),
"requests": result.summary.requests.iter().map(syntax_inspect_request_summary_json).collect::<Vec<_>>(),
"symbols": syntax_symbol_table_json(&result.summary.symbols),
})
}
pub fn hen_error_json(error: &HenError) -> Value {
json!({
"error": {
"kind": error.kind().label(),
"summary": error.summary(),
"details": error.details(),
"diagnostics": error.diagnostics().iter().map(hen_diagnostic_json).collect::<Vec<_>>(),
"exitCode": error.exit_code(),
}
})
}
fn verification_legacy_error_json(error: &HenError) -> Value {
json!({
"kind": error.kind().label(),
"summary": error.summary(),
"details": error.details(),
"diagnostics": error.diagnostics().iter().map(hen_diagnostic_json).collect::<Vec<_>>(),
"exitCode": error.exit_code(),
})
}
fn syntax_summary_json(summary: &crate::parser::SyntaxSummary) -> Value {
json!({
"name": summary.name,
"description": summary.description,
"availableEnvironments": summary.available_environments,
"requests": summary.requests.iter().map(syntax_request_summary_json).collect::<Vec<_>>(),
})
}
fn syntax_request_summary_json(request: &crate::parser::SyntaxRequestSummary) -> Value {
json!({
"index": request.index,
"description": request.description,
"method": request.method,
"url": request.url,
"protocol": request.protocol,
"protocolContext": request.protocol_context,
})
}
fn syntax_declaration_summary_json(
declaration: &crate::parser::SyntaxDeclarationSummary,
) -> Value {
json!({
"kind": declaration.kind,
"name": declaration.name,
"range": syntax_range_summary_json(&declaration.range),
})
}
fn syntax_fragment_include_summary_json(
include: &crate::parser::SyntaxFragmentIncludeSummary,
) -> Value {
json!({
"path": include.path,
"guard": include.guard,
"assertionIndex": include.assertion_index,
"range": syntax_range_summary_json(&include.range),
})
}
fn syntax_inspect_request_summary_json(
request: &crate::parser::SyntaxInspectRequestSummary,
) -> Value {
json!({
"index": request.index,
"description": request.description,
"method": request.method,
"url": request.url,
"protocol": request.protocol,
"protocolContext": request.protocol_context,
"dependencies": request.dependencies,
"fragmentIncludes": request.fragment_includes.iter().map(syntax_fragment_include_summary_json).collect::<Vec<_>>(),
"sessionName": request.session_name,
"authProfile": request.auth_profile,
})
}
fn syntax_symbol_table_json(symbols: &crate::parser::SyntaxSymbolTable) -> Value {
json!({
"requests": symbols.requests,
"schemas": symbols.schemas,
"scalars": symbols.scalars,
"environments": symbols.environments,
"oauthProfiles": symbols.oauth_profiles,
"sessions": symbols.sessions,
})
}
fn syntax_range_summary_json(range: &crate::parser::SyntaxRangeSummary) -> Value {
json!({
"start": syntax_position_summary_json(&range.start),
"end": syntax_position_summary_json(&range.end),
})
}
fn syntax_position_summary_json(position: &crate::parser::SyntaxPositionSummary) -> Value {
json!({
"line": position.line,
"character": position.character,
})
}
pub(crate) fn hen_diagnostic_json(diagnostic: &HenDiagnostic) -> Value {
json!({
"code": diagnostic.code,
"severity": diagnostic.severity.label(),
"phase": diagnostic.phase.label(),
"message": diagnostic.message,
"source": diagnostic.source,
"location": hen_diagnostic_location_json(&diagnostic.location),
"relatedInformation": diagnostic.related_information.iter().map(hen_diagnostic_related_information_json).collect::<Vec<_>>(),
"symbol": diagnostic.symbol.as_ref().map(hen_diagnostic_symbol_json),
"suggestions": diagnostic.suggestions.iter().map(hen_diagnostic_suggestion_json).collect::<Vec<_>>(),
"data": diagnostic.data.clone(),
})
}
fn hen_diagnostic_symbol_json(symbol: &HenDiagnosticSymbol) -> Value {
json!({
"kind": symbol.kind,
"name": symbol.name,
"role": symbol.role,
})
}
fn hen_diagnostic_suggestion_json(suggestion: &HenDiagnosticSuggestion) -> Value {
json!({
"kind": suggestion.kind,
"label": suggestion.label,
"range": suggestion.range.as_ref().map(hen_diagnostic_range_json),
"text": suggestion.text,
})
}
fn hen_diagnostic_related_information_json(
related: &HenDiagnosticRelatedInformation,
) -> Value {
json!({
"message": related.message,
"location": hen_diagnostic_location_json(&related.location),
})
}
fn hen_diagnostic_location_json(location: &HenDiagnosticLocation) -> Value {
json!({
"path": location.path,
"range": hen_diagnostic_range_json(&location.range),
})
}
fn hen_diagnostic_range_json(range: &HenDiagnosticRange) -> Value {
json!({
"start": hen_diagnostic_position_json(&range.start),
"end": hen_diagnostic_position_json(&range.end),
})
}
fn hen_diagnostic_position_json(position: &HenDiagnosticPosition) -> Value {
json!({
"line": position.line,
"character": position.character,
})
}
fn prompt_requirement_json(prompt: &PromptRequirement) -> Value {
json!({
"name": prompt.name,
"default": prompt.default,
})
}