use crate::resolution::types::{ResolutionContext, ResolvedBy, ResolvedRef, UnresolvedRef};
use crate::types::NodeKind;
use super::common::{resolved, shared_char_prefix};
pub(super) fn resolve_lua_require(
reference: &UnresolvedRef,
context: &mut dyn ResolutionContext,
) -> Option<ResolvedRef> {
let name = reference.reference_name.as_str();
if name.is_empty() {
return None;
}
let base = if name.contains('.') {
name.replace('.', "/")
} else {
name.to_string()
};
let suffixes = [
format!("{base}.lua"),
format!("{base}.luau"),
format!("{base}/init.lua"),
format!("{base}/init.luau"),
];
for suffix in suffixes {
let mut matches = context
.get_all_files()
.into_iter()
.filter(|file| file == &suffix || file.ends_with(&format!("/{suffix}")))
.collect::<Vec<_>>();
if matches.is_empty() {
continue;
}
matches
.sort_by_key(|file| std::cmp::Reverse(shared_char_prefix(file, &reference.file_path)));
let best = matches[0].clone();
if best == reference.file_path {
continue;
}
if let Some(file_node) = context
.get_nodes_in_file(&best)
.into_iter()
.find(|n| n.kind == NodeKind::File)
{
return Some(resolved(reference, &file_node.id, 0.9, ResolvedBy::Import));
}
}
None
}
pub(super) fn resolve_ruby_require(
reference: &UnresolvedRef,
context: &mut dyn ResolutionContext,
) -> Option<ResolvedRef> {
let name = reference.reference_name.trim();
if name.is_empty() {
return None;
}
let source_line = context
.read_file(&reference.file_path)
.and_then(|content| {
content
.lines()
.nth(reference.line.saturating_sub(1) as usize)
.map(str::to_owned)
})
.unwrap_or_default();
let require_relative = source_line.contains("require_relative");
let base = name.trim_start_matches("./").trim_end_matches(".rb");
let suffixes = [format!("{base}.rb"), format!("{base}/init.rb")];
let from_dir = reference
.file_path
.rsplit_once('/')
.map(|(dir, _)| dir)
.unwrap_or("");
for suffix in suffixes {
let wanted = if require_relative && !from_dir.is_empty() {
format!("{from_dir}/{suffix}")
} else {
suffix.clone()
};
let mut matches = context
.get_all_files()
.into_iter()
.filter(|file| file == &wanted || file.ends_with(&format!("/{wanted}")))
.collect::<Vec<_>>();
if matches.is_empty() && !require_relative {
matches = context
.get_all_files()
.into_iter()
.filter(|file| file == &suffix || file.ends_with(&format!("/{suffix}")))
.collect::<Vec<_>>();
}
if matches.is_empty() {
continue;
}
matches
.sort_by_key(|file| std::cmp::Reverse(shared_char_prefix(file, &reference.file_path)));
let best = matches[0].clone();
if best == reference.file_path {
continue;
}
if let Some(file_node) = context
.get_nodes_in_file(&best)
.into_iter()
.find(|node| node.kind == NodeKind::File)
{
return Some(resolved(reference, &file_node.id, 0.9, ResolvedBy::Import));
}
}
None
}