Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: resolve_import #79

Merged
merged 6 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions rs-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use url::Url;

#[cfg(feature = "ext")]
pub mod ext;
pub mod specifier;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ImportMapDiagnostic {
Expand Down Expand Up @@ -1118,6 +1119,8 @@ fn resolve_imports_match(
return Ok(Some(url));
}

log::debug!("Backtrace: {}", std::backtrace::Backtrace::force_capture());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this on purpose or left by accident?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accident. I don’t remember writing this lol

dsherret marked this conversation as resolved.
Show resolved Hide resolved

dsherret marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(feature = "logging")]
log::debug!(
"Specifier {:?} was not mapped in import map.",
Expand Down
79 changes: 79 additions & 0 deletions rs-lib/src/specifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2018-2024 the Deno authors. MIT license.

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 ../",
),
}
}
}

/// Given a specifier string and a referring module specifier, try to resolve
/// the target module specifier, erroring if it cannot be resolved.
///
/// This function is useful for resolving specifiers in situations without an
/// import map.
pub fn resolve_import(
specifier: &str,
referrer: &Url,
) -> Result<Url, SpecifierError> {
match Url::parse(specifier) {
// 1. Apply the URL parser to specifier.
// If the result is not failure, return he result.
Ok(url) => Ok(url),

// 2. If specifier does not start with the character U+002F SOLIDUS (/),
// the two-character sequence U+002E FULL STOP, U+002F SOLIDUS (./),
// or the three-character sequence U+002E FULL STOP, U+002E FULL STOP,
// U+002F SOLIDUS (../), return failure.
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()),
})
}

// 3. Return the result of applying the URL parser to specifier with base
// URL as the base URL.
Err(url::ParseError::RelativeUrlWithoutBase) => {
referrer.join(specifier).map_err(SpecifierError::InvalidUrl)
}

// If parsing the specifier as a URL failed for a different reason than
// it being relative, always return the original error. We don't want to
// return `ImportPrefixMissing` or `InvalidBaseUrl` if the real
// problem lies somewhere else.
Err(err) => Err(SpecifierError::InvalidUrl(err)),
}
}
Loading