use std::error::Error;
use std::fmt;
use url::Url;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SpecifierError {
InvalidUrl(url::ParseError),
ImportPrefixMissing {
specifier: String,
referrer: Option<Url>,
},
}
impl Error for SpecifierError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::InvalidUrl(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for SpecifierError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::InvalidUrl(ref err) => write!(f, "invalid URL: {err}"),
Self::ImportPrefixMissing { specifier, .. } => write!(
f,
"Relative import path \"{specifier}\" not prefixed with / or ./ or ../",
),
}
}
}
pub fn resolve_import(
specifier: &str,
referrer: &Url,
) -> Result<Url, SpecifierError> {
match Url::parse(specifier) {
Ok(url) => Ok(url),
Err(url::ParseError::RelativeUrlWithoutBase)
if !(specifier.starts_with('/')
|| specifier.starts_with("./")
|| specifier.starts_with("../")) =>
{
Err(SpecifierError::ImportPrefixMissing {
specifier: specifier.to_string(),
referrer: Some(referrer.clone()),
})
}
Err(url::ParseError::RelativeUrlWithoutBase) => {
referrer.join(specifier).map_err(SpecifierError::InvalidUrl)
}
Err(err) => Err(SpecifierError::InvalidUrl(err)),
}
}