use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use streaming_iterator::StreamingIterator;
use tree_sitter::{Language, Node, Parser, Query, QueryCursor, Tree};
pub mod kotlin;
pub mod swift;
#[derive(Debug, Clone)]
pub struct Import {
pub specifier: String,
pub line: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Target {
Internal(PathBuf),
External(String),
}
pub trait Adapter {
fn name(&self) -> &'static str;
fn handles(&self, path: &Path) -> bool;
fn imports(&self, path: &Path, source: &str) -> Result<Vec<Import>>;
fn resolve(&self, file: &Path, specifier: &str) -> Target;
}
pub fn adapters(root: &Path) -> Result<Vec<Box<dyn Adapter>>> {
Ok(vec![
Box::new(kotlin::Kotlin::new(root)?),
Box::new(swift::Swift::new(root)?),
])
}
pub(crate) fn parse(language: &Language, path: &Path, source: &str) -> Result<Tree> {
let mut parser = Parser::new();
parser.set_language(language)?;
parser
.parse(source, None)
.with_context(|| format!("cannot parse {}", path.display()))
}
pub(crate) fn captured_nodes<'t>(query: &Query, tree: &'t Tree, source: &str) -> Vec<Node<'t>> {
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(query, tree.root_node(), source.as_bytes());
let mut nodes = Vec::new();
while let Some(m) = matches.next() {
nodes.extend(m.captures().iter().map(|c| c.node));
}
nodes
}
pub fn relative(root: &Path, path: &Path) -> Option<PathBuf> {
path.strip_prefix(root).ok().map(Path::to_path_buf)
}