use std::collections::HashMap;
use std::path::Path;
use crate::graph;
use crate::suggest::kind_rank;
use super::refs::trim_source;
pub fn source_line(root: &Path, file: &str, line: usize) -> String {
let Ok(body) = std::fs::read_to_string(root.join(file)) else {
return String::new();
};
let lines: Vec<&str> = body.split('\n').collect();
if line < 1 || line > lines.len() {
return String::new();
}
let mut raw = lines[line - 1];
if line == 1 {
raw = raw.strip_prefix('\u{feff}').unwrap_or(raw);
}
trim_source(raw).to_string()
}
pub fn find_names<'g>(graph: &'g graph::Graph, query: &str) -> Vec<&'g graph::GraphName> {
let tokens: Vec<String> = query
.to_lowercase()
.split_whitespace()
.map(String::from)
.collect();
if tokens.is_empty() {
return Vec::new();
}
graph
.names
.iter()
.filter(|n| {
let hay = n.name.to_lowercase();
tokens.iter().all(|t| hay.contains(t.as_str()))
})
.collect()
}
pub fn first_decl_line_by_file(graph: &graph::Graph) -> HashMap<String, usize> {
let mut lines: HashMap<String, usize> = HashMap::new();
for n in &graph.names {
lines
.entry(n.file.clone())
.and_modify(|line| *line = (*line).min(n.line))
.or_insert(n.line);
}
lines
}
pub fn file_inbound_counts(graph: &graph::Graph) -> HashMap<String, usize> {
let mut counts: HashMap<String, usize> = HashMap::new();
for e in &graph.edges {
let (from_file, to_file) = match e {
graph::Edge::Inherits {
from_file,
to_file,
heuristic,
..
}
| graph::Edge::UsesType {
from_file,
to_file,
heuristic,
..
}
| graph::Edge::UsesMember {
from_file,
to_file,
heuristic,
..
} => {
if *heuristic {
continue;
}
(from_file, to_file)
}
graph::Edge::Call {
from_file, to_file, ..
}
| graph::Edge::JsxUse {
from_file, to_file, ..
}
| graph::Edge::Dispatch {
from_file, to_file, ..
} => (from_file, to_file),
graph::Edge::Imports { .. }
| graph::Edge::Import { .. }
| graph::Edge::CtorDi { .. }
| graph::Edge::Implements { .. }
| graph::Edge::Overrides { .. }
| graph::Edge::Ambiguous { .. } => continue,
};
if from_file == to_file {
continue;
}
*counts.entry(to_file.clone()).or_insert(0) += 1;
}
counts
}
pub fn name_tier(kind: &str) -> u8 {
let rank = kind_rank(kind);
if rank <= 1 {
1
} else {
rank
}
}