diff options
Diffstat (limited to 'cli/fs_util.rs')
-rw-r--r-- | cli/fs_util.rs | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/cli/fs_util.rs b/cli/fs_util.rs index fe0ef8857..578a2ec37 100644 --- a/cli/fs_util.rs +++ b/cli/fs_util.rs @@ -5,6 +5,7 @@ use deno_core::error::{uri_error, AnyError}; pub use deno_core::normalize_path; use deno_core::ModuleSpecifier; use deno_runtime::deno_crypto::rand; +use std::borrow::Cow; use std::env::current_dir; use std::fs::OpenOptions; use std::io::{Error, Write}; @@ -362,6 +363,44 @@ pub fn specifier_parent(specifier: &ModuleSpecifier) -> ModuleSpecifier { specifier } +/// `from.make_relative(to)` but with fixes. +pub fn relative_specifier( + from: &ModuleSpecifier, + to: &ModuleSpecifier, +) -> Option<String> { + let is_dir = to.path().ends_with('/'); + + if is_dir && from == to { + return Some("./".to_string()); + } + + // workaround using parent directory until https://github.com/servo/rust-url/pull/754 is merged + let from = if !from.path().ends_with('/') { + if let Some(end_slash) = from.path().rfind('/') { + let mut new_from = from.clone(); + new_from.set_path(&from.path()[..end_slash + 1]); + Cow::Owned(new_from) + } else { + Cow::Borrowed(from) + } + } else { + Cow::Borrowed(from) + }; + + // workaround for url crate not adding a trailing slash for a directory + // it seems to be fixed once a version greater than 2.2.2 is released + let mut text = from.make_relative(to)?; + if is_dir && !text.ends_with('/') && to.query().is_none() { + text.push('/'); + } + + Some(if text.starts_with("../") || text.starts_with("./") { + text + } else { + format!("./{}", text) + }) +} + /// This function checks if input path has trailing slash or not. If input path /// has trailing slash it will return true else it will return false. pub fn path_has_trailing_slash(path: &Path) -> bool { @@ -749,6 +788,39 @@ mod tests { } #[test] + fn test_relative_specifier() { + run_test("file:///from", "file:///to", Some("./to")); + run_test("file:///from", "file:///from/other", Some("./from/other")); + run_test("file:///from", "file:///from/other/", Some("./from/other/")); + run_test("file:///from", "file:///other/from", Some("./other/from")); + run_test("file:///from/", "file:///other/from", Some("../other/from")); + run_test("file:///from", "file:///other/from/", Some("./other/from/")); + run_test( + "file:///from", + "file:///to/other.txt", + Some("./to/other.txt"), + ); + run_test( + "file:///from/test", + "file:///to/other.txt", + Some("../to/other.txt"), + ); + run_test( + "file:///from/other.txt", + "file:///to/other.txt", + Some("../to/other.txt"), + ); + + fn run_test(from: &str, to: &str, expected: Option<&str>) { + let result = relative_specifier( + &ModuleSpecifier::parse(from).unwrap(), + &ModuleSpecifier::parse(to).unwrap(), + ); + assert_eq!(result.as_deref(), expected); + } + } + + #[test] fn test_path_has_trailing_slash() { #[cfg(not(windows))] { |