diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2020-07-16 10:53:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-16 10:53:07 +0200 |
commit | 98e0ed54db5bbd8befcb5afbb1d63f2b80677f51 (patch) | |
tree | 7f8ab9b27a75840ed08ea6d4c33576f1886b3c6d /core/module_specifier.rs | |
parent | b0f2bd4a2d1a75d7c8e4643a4b5b9478c1935668 (diff) |
fix: ModuleSpecifier removes relative path parts (#6762)
Diffstat (limited to 'core/module_specifier.rs')
-rw-r--r-- | core/module_specifier.rs | 67 |
1 files changed, 65 insertions, 2 deletions
diff --git a/core/module_specifier.rs b/core/module_specifier.rs index 9cf449302..1ad4bcc93 100644 --- a/core/module_specifier.rs +++ b/core/module_specifier.rs @@ -1,6 +1,8 @@ use std::env::current_dir; use std::error::Error; use std::fmt; +use std::path::Component; +use std::path::Path; use std::path::PathBuf; use url::ParseError; use url::Url; @@ -150,6 +152,7 @@ impl ModuleSpecifier { path_str: &str, ) -> Result<ModuleSpecifier, ModuleResolutionError> { let path = current_dir().unwrap().join(path_str); + let path = normalize_path(&path); Url::from_file_path(path.clone()) .map(ModuleSpecifier) .map_err(|()| ModuleResolutionError::InvalidPath(path)) @@ -203,6 +206,39 @@ impl PartialEq<String> for ModuleSpecifier { } } +/// Normalize all itermediate components of the path (ie. remove "./" and "../" components). +/// Similar to `fs::canonicalize()` but doesn't resolve symlinks. +/// +/// Taken from Cargo +/// https://github.com/rust-lang/cargo/blob/af307a38c20a753ec60f0ad18be5abed3db3c9ac/src/cargo/util/paths.rs#L60-L85 +pub fn normalize_path(path: &Path) -> PathBuf { + let mut components = path.components().peekable(); + let mut ret = + if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { + components.next(); + PathBuf::from(c.as_os_str()) + } else { + PathBuf::new() + }; + + for component in components { + match component { + Component::Prefix(..) => unreachable!(), + Component::RootDir => { + ret.push(component.as_os_str()); + } + Component::CurDir => {} + Component::ParentDir => { + ret.pop(); + } + Component::Normal(c) => { + ret.push(c); + } + } + } + ret +} + #[cfg(test)] mod tests { use super::*; @@ -415,7 +451,12 @@ mod tests { ); tests.extend(vec![ (r"/deno/tests/006_url_imports.ts", expected_url.to_string()), - (r"\deno\tests\006_url_imports.ts", expected_url), + (r"\deno\tests\006_url_imports.ts", expected_url.to_string()), + ( + r"\deno\..\deno\tests\006_url_imports.ts", + expected_url.to_string(), + ), + (r"\deno\.\tests\006_url_imports.ts", expected_url), ]); // Relative local path. @@ -450,7 +491,12 @@ mod tests { let expected_url = format!("file://{}/tests/006_url_imports.ts", cwd_str); tests.extend(vec![ ("tests/006_url_imports.ts", expected_url.to_string()), - ("./tests/006_url_imports.ts", expected_url), + ("./tests/006_url_imports.ts", expected_url.to_string()), + ( + "tests/../tests/006_url_imports.ts", + expected_url.to_string(), + ), + ("tests/./006_url_imports.ts", expected_url), ]); } @@ -511,4 +557,21 @@ mod tests { assert_eq!(result, expected); } } + + #[test] + fn test_normalize_path() { + assert_eq!(normalize_path(Path::new("a/../b")), PathBuf::from("b")); + assert_eq!(normalize_path(Path::new("a/./b/")), PathBuf::from("a/b/")); + assert_eq!( + normalize_path(Path::new("a/./b/../c")), + PathBuf::from("a/c") + ); + + if cfg!(windows) { + assert_eq!( + normalize_path(Path::new("C:\\a\\.\\b\\..\\c")), + PathBuf::from("C:\\a\\c") + ); + } + } } |