use super::OutputFormatter;
use crate::dns::{DnsRecord, FollowIteration, FollowResult, PropagationResult};
use crate::lookup::LookupResult;
use crate::rdap::RdapResponse;
use crate::status::StatusResponse;
use crate::whois::WhoisResponse;
pub struct JsonFormatter {
pretty: bool,
}
impl Default for JsonFormatter {
fn default() -> Self {
Self::new()
}
}
impl JsonFormatter {
pub fn new() -> Self {
Self { pretty: true }
}
pub fn compact(mut self) -> Self {
self.pretty = false;
self
}
fn to_json<T: serde::Serialize + ?Sized>(&self, value: &T) -> String {
if self.pretty {
serde_json::to_string_pretty(value)
.unwrap_or_else(|e| format!("{{\"error\": \"{}\"}}", e))
} else {
serde_json::to_string(value).unwrap_or_else(|e| format!("{{\"error\": \"{}\"}}", e))
}
}
}
impl OutputFormatter for JsonFormatter {
fn format_whois(&self, response: &WhoisResponse) -> String {
self.to_json(response)
}
fn format_rdap(&self, response: &RdapResponse) -> String {
self.to_json(response)
}
fn format_dns(&self, records: &[DnsRecord]) -> String {
self.to_json(records)
}
fn format_propagation(&self, result: &PropagationResult) -> String {
self.to_json(result)
}
fn format_lookup(&self, result: &LookupResult) -> String {
self.to_json(result)
}
fn format_status(&self, response: &StatusResponse) -> String {
self.to_json(response)
}
fn format_follow_iteration(&self, iteration: &FollowIteration) -> String {
self.to_json(iteration)
}
fn format_follow(&self, result: &FollowResult) -> String {
self.to_json(result)
}
fn format_availability(&self, result: &crate::availability::AvailabilityResult) -> String {
self.to_json(result)
}
fn format_dnssec(&self, report: &crate::dns::DnssecReport) -> String {
self.to_json(report)
}
fn format_tld(&self, info: &crate::tld::TldInfo) -> String {
self.to_json(info)
}
fn format_dns_comparison(&self, comparison: &crate::dns::DnsComparison) -> String {
self.to_json(comparison)
}
fn format_subdomains(&self, result: &crate::subdomains::SubdomainResult) -> String {
self.to_json(result)
}
fn format_diff(&self, diff: &crate::diff::DomainDiff) -> String {
self.to_json(diff)
}
fn format_ssl(&self, report: &crate::ssl::SslReport) -> String {
self.to_json(report)
}
fn format_watch(&self, report: &crate::watchlist::WatchReport) -> String {
self.to_json(report)
}
fn format_domain_info(&self, info: &crate::domain_info::DomainInfo) -> String {
self.to_json(info)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dns::RecordType;
use crate::status::StatusResponse;
#[test]
fn test_json_format_status() {
let response = StatusResponse::new("example.com".to_string());
let formatter = JsonFormatter::new();
let output = formatter.format_status(&response);
assert!(output.contains("example.com"));
assert!(output.contains("domain"));
}
#[test]
fn test_json_compact() {
let response = StatusResponse::new("example.com".to_string());
let formatter = JsonFormatter::new().compact();
let output = formatter.format_status(&response);
assert!(!output.contains("\n "));
}
#[test]
fn test_json_format_dns_records() {
let records = vec![DnsRecord {
name: "example.com".to_string(),
record_type: RecordType::A,
ttl: 300,
data: crate::dns::RecordData::A {
address: "93.184.216.34".to_string(),
},
}];
let formatter = JsonFormatter::new();
let output = formatter.format_dns(&records);
assert!(output.contains("93.184.216.34"));
assert!(output.contains("\"A\""));
}
}