summaryrefslogtreecommitdiff
path: root/cli/fs_util.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/fs_util.rs')
-rw-r--r--cli/fs_util.rs72
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))]
{