MCPcopy Create free account
hub / github.com/ScriptedAlchemy/tracedecay / build_file_adjacency

Method build_file_adjacency

src/graph/queries.rs:446–506  ·  view source on GitHub ↗

Builds a file-level directed adjacency map from the code graph. For each file, collects the files it depends on via `calls` and `uses` (imports) edges. Self-edges are excluded. `implements` and `extends` are intentionally **not** followed: the Rust resolver fuzzy-binds `impl Debug for T` and similar to whatever node happens to share the trait's short name, which on real codebases produces long ch

(
        &self,
        path_prefix: Option<&str>,
    )

Source from the content-addressed store, hash-verified

444 /// When `path_prefix` is `Some`, only files under that prefix are included
445 /// (both as sources and targets).
446 pub async fn build_file_adjacency(
447 &self,
448 path_prefix: Option<&str>,
449 ) -> Result<HashMap<String, HashSet<String>>> {
450 let sql = "SELECT DISTINCT n1.file_path AS src_file, n2.file_path AS tgt_file \
451 FROM edges e \
452 JOIN nodes n1 ON e.source = n1.id \
453 JOIN nodes n2 ON e.target = n2.id \
454 WHERE e.kind IN ('calls', 'uses') \
455 AND n1.file_path != n2.file_path";
456
457 let mut rows =
458 self.db
459 .conn()
460 .query(sql, ())
461 .await
462 .map_err(|e| TraceDecayError::Database {
463 message: format!("failed to query file adjacency: {e}"),
464 operation: "build_file_adjacency".to_string(),
465 })?;
466
467 // Normalise the prefix once: ensure it ends with '/'.
468 let prefix: Option<String> = path_prefix.map(|p| {
469 if p.ends_with('/') {
470 p.to_string()
471 } else {
472 format!("{p}/")
473 }
474 });
475
476 let mut adj: HashMap<String, HashSet<String>> = HashMap::new();
477
478 while let Some(row) = rows.next().await.map_err(|e| TraceDecayError::Database {
479 message: format!("failed to read adjacency row: {e}"),
480 operation: "build_file_adjacency".to_string(),
481 })? {
482 let src: String = row.get(0).unwrap_or_default();
483 let tgt: String = row.get(1).unwrap_or_default();
484
485 if let Some(ref pfx) = prefix {
486 if !src.starts_with(pfx.as_str()) || !tgt.starts_with(pfx.as_str()) {
487 continue;
488 }
489 }
490
491 adj.entry(src).or_default().insert(tgt);
492 }
493
494 // Ensure every known file appears as a key (even leaf nodes with no deps).
495 let all_files = self.db.get_all_files().await?;
496 for file in all_files {
497 if let Some(ref pfx) = prefix {
498 if !file.path.starts_with(pfx.as_str()) {
499 continue;
500 }
501 }
502 adj.entry(file.path).or_default();
503 }

Callers 5

compute_health_snapshotFunction · 0.80
handle_dependency_depthFunction · 0.80
handle_dsmFunction · 0.80

Calls 5

insertMethod · 0.80
entryMethod · 0.80
connMethod · 0.45
as_strMethod · 0.45
get_all_filesMethod · 0.45