use std::path::Path;
use std::sync::OnceLock;
use anyhow::Result;
use crate::parse::ModuleFacts;
use crate::resolve::{Resolution, ResolveCtx};
mod javascript;
use javascript::JavaScriptAdapter;
#[cfg(any(feature = "vue", feature = "svelte"))]
mod component;
#[cfg(feature = "svelte")]
use component::SvelteAdapter;
#[cfg(feature = "vue")]
use component::VueAdapter;
#[cfg(feature = "python")]
mod python;
#[cfg(feature = "python")]
use python::PythonAdapter;
#[cfg(feature = "rust")]
mod rust_lang;
#[cfg(feature = "rust")]
use rust_lang::RustAdapter;
pub(crate) trait LanguageAdapter: Send + Sync {
fn extensions(&self) -> &'static [&'static str];
fn handles(&self, path: &Path) -> bool {
path.extension()
.and_then(|ext| ext.to_str())
.is_some_and(|ext| self.extensions().contains(&ext))
}
fn parse(&self, path: &Path, source: &str) -> Result<ModuleFacts>;
fn resolve(&self, ctx: &ResolveCtx, importer: &Path, specifier: &str) -> Resolution;
fn is_internal(&self, ctx: &ResolveCtx, importer: &Path, specifier: &str) -> bool;
}
fn registry() -> &'static [Box<dyn LanguageAdapter>] {
static REGISTRY: OnceLock<Vec<Box<dyn LanguageAdapter>>> = OnceLock::new();
REGISTRY.get_or_init(|| {
#[allow(unused_mut)]
let mut adapters: Vec<Box<dyn LanguageAdapter>> = vec![Box::new(JavaScriptAdapter)];
#[cfg(feature = "python")]
adapters.push(Box::new(PythonAdapter));
#[cfg(feature = "rust")]
adapters.push(Box::new(RustAdapter));
#[cfg(feature = "vue")]
adapters.push(Box::new(VueAdapter));
#[cfg(feature = "svelte")]
adapters.push(Box::new(SvelteAdapter));
adapters
})
}
pub(crate) fn adapter_for(path: &Path) -> &'static dyn LanguageAdapter {
let registry = registry();
registry
.iter()
.find(|adapter| adapter.handles(path))
.unwrap_or(®istry[0])
.as_ref()
}
fn source_extensions() -> &'static [&'static str] {
static EXTENSIONS: OnceLock<Vec<&'static str>> = OnceLock::new();
EXTENSIONS.get_or_init(|| {
registry()
.iter()
.flat_map(|adapter| adapter.extensions().iter().copied())
.collect()
})
}
pub(crate) fn is_source_extension(ext: &str) -> bool {
source_extensions().contains(&ext)
}