use crate::catalog::scan::ScanMode;
use crate::listing::Format;
pub(crate) struct InspectArgs<'a> {
pub id: &'a str,
pub format: Format,
pub json: bool,
pub transitive: bool,
pub direction: crate::relation_graph::TransitiveDir,
pub labels: Vec<String>,
pub max_depth: Option<String>,
}
fn parse_max_depth(raw: Option<&str>) -> anyhow::Result<Option<usize>> {
match raw {
None => Ok(Some(5)),
Some("0" | "all") => Ok(None),
Some(s) => {
let n = s.parse::<usize>().map_err(|_err| {
anyhow::anyhow!("--max-depth must be a non-negative integer or `all`, got `{s}`")
})?;
Ok(Some(n))
}
}
}
pub(crate) fn run_inspect(
path: Option<std::path::PathBuf>,
args: &InspectArgs<'_>,
) -> anyhow::Result<()> {
use std::io::{self, Write};
let root = crate::root::find(path, &crate::root::default_markers())?;
let resolved = if args.json { Format::Json } else { args.format };
let id = args.id;
let is_memory_ref = matches!(
crate::memory::MemoryRef::parse(id),
Ok(crate::memory::MemoryRef::Uid(_)
| crate::memory::MemoryRef::UidPrefix(_)
| crate::memory::MemoryRef::Key(_))
);
if args.transitive && is_memory_ref {
anyhow::bail!(
"{id}: --transitive operates on the entity relation graph; \
for the memory graph use `doctrine memory retrieve --expand <N>`"
);
}
if is_memory_ref {
let uid = crate::memory::resolve_inspect_uid(&root, id)?;
let out = crate::memory::memory_inspect_view(&root, &uid, resolved)?;
write!(std::io::stdout(), "{out}")?;
return Ok(());
}
let mut diagnostics = Vec::new();
let scanned =
crate::relation_graph::scan_entities(&root, &mut diagnostics, ScanMode::default())?;
for diag in &diagnostics {
writeln!(io::stderr(), "{}: {}", diag.file.display(), diag.message)?;
}
if args.transitive {
let labels = crate::relation_graph::resolve_transitive_label_names(&args.labels)?;
let max_depth = parse_max_depth(args.max_depth.as_deref())?;
let view = crate::relation_graph::transitive_from(
&scanned,
&root,
id,
args.direction,
labels.as_deref(),
max_depth,
)?;
let out = match resolved {
Format::Table => crate::relation_graph::render_transitive_human(&view),
Format::Json => crate::relation_graph::render_transitive_json(&view)?,
};
write!(std::io::stdout(), "{out}")?;
return Ok(());
}
let out = match resolved {
Format::Table => {
let relation = crate::relation_graph::render_from(&scanned, &root, id, Format::Table)?;
let block = crate::priority::surface::actionability_block_from(&scanned, &root, id)?;
let block = crate::priority::render::actionability_block_human(&block);
format!("{relation}{block}")
}
Format::Json => {
let view = crate::relation_graph::inspect_from(&scanned, &root, id)?;
let block = crate::priority::surface::actionability_block_from(&scanned, &root, id)?;
let mut value = crate::relation_graph::inspect_value(&view);
if let Some(obj) = value.as_object_mut() {
obj.insert(
"actionability".to_string(),
crate::priority::render::actionability_block_value(&block),
);
}
serde_json::to_string_pretty(&value)
.map_err(|e| anyhow::anyhow!("failed to serialize inspect JSON: {e}"))?
}
};
write!(std::io::stdout(), "{out}")?;
Ok(())
}