diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9962e44..1814e55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,3 +28,14 @@ jobs: - run: cargo check - run: cargo test + + fmt: + runs-on: ubuntu-latest + steps: + - uses: taiki-e/checkout-action@v1 + + - uses: oxc-project/setup-rust@v1.0.0 + with: + components: rustfmt + + - run: cargo fmt --check diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..d6b90a3 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,2 @@ +style_edition = "2024" +use_small_heuristics = "Max" diff --git a/src/fs.rs b/src/fs.rs index 74fc257..5312d23 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,5 +1,8 @@ use serde::Deserialize; -use std::{path::{Path, PathBuf}, str::Utf8Error}; +use std::{ + path::{Path, PathBuf}, + str::Utf8Error, +}; use crate::zip::Zip; @@ -79,18 +82,14 @@ pub enum Error { pub fn open_zip_via_mmap>(p: P) -> Result, std::io::Error> { let file = fs::File::open(p)?; - let mmap_builder = mmap_rs::MmapOptions::new(file.metadata().unwrap().len().try_into().unwrap()) - .unwrap(); + let mmap_builder = + mmap_rs::MmapOptions::new(file.metadata().unwrap().len().try_into().unwrap()).unwrap(); - let mmap = unsafe { - mmap_builder - .with_file(file, 0) - .map() - .unwrap() - }; + let mmap = unsafe { mmap_builder.with_file(file, 0).map().unwrap() }; - let zip = Zip::new(mmap) - .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Failed to read the zip file"))?; + let zip = Zip::new(mmap).map_err(|_| { + std::io::Error::new(std::io::ErrorKind::Other, "Failed to read the zip file") + })?; Ok(zip) } @@ -103,8 +102,9 @@ pub fn open_zip_via_mmap_p(p: &Path) -> Result, std::io::Erro pub fn open_zip_via_read>(p: P) -> Result>, std::io::Error> { let data = std::fs::read(p)?; - let zip = Zip::new(data) - .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Failed to read the zip file"))?; + let zip = Zip::new(data).map_err(|_| { + std::io::Error::new(std::io::ErrorKind::Other, "Failed to read the zip file") + })?; Ok(zip) } @@ -114,50 +114,85 @@ pub fn open_zip_via_read_p(p: &Path) -> Result>, std::io::Error> { } pub trait ZipCache -where Storage: AsRef<[u8]> + Send + Sync { - fn act, F : FnOnce(&Zip) -> T>(&self, p: P, cb: F) -> Result; - - fn file_type, S: AsRef>(&self, zip_path: P, sub: S) -> Result; - fn read, S: AsRef>(&self, zip_path: P, sub: S) -> Result, std::io::Error>; - fn read_to_string, S: AsRef>(&self, zip_path: P, sub: S) -> Result; +where + Storage: AsRef<[u8]> + Send + Sync, +{ + fn act, F: FnOnce(&Zip) -> T>( + &self, + p: P, + cb: F, + ) -> Result; + + fn file_type, S: AsRef>( + &self, + zip_path: P, + sub: S, + ) -> Result; + fn read, S: AsRef>( + &self, + zip_path: P, + sub: S, + ) -> Result, std::io::Error>; + fn read_to_string, S: AsRef>( + &self, + zip_path: P, + sub: S, + ) -> Result; } #[derive(Debug)] pub struct LruZipCache -where Storage: AsRef<[u8]> + Send + Sync { +where + Storage: AsRef<[u8]> + Send + Sync, +{ lru: concurrent_lru::sharded::LruCache>, open: fn(&Path) -> std::io::Result>, } impl LruZipCache -where Storage: AsRef<[u8]> + Send + Sync { +where + Storage: AsRef<[u8]> + Send + Sync, +{ pub fn new(n: u64, open: fn(&Path) -> std::io::Result>) -> LruZipCache { - LruZipCache { - lru: concurrent_lru::sharded::LruCache::new(n), - open, - } + LruZipCache { lru: concurrent_lru::sharded::LruCache::new(n), open } } } impl ZipCache for LruZipCache -where Storage: AsRef<[u8]> + Send + Sync { - fn act, F: FnOnce(&Zip) -> T>(&self, p: P, cb: F) -> Result { - let zip = self.lru.get_or_try_init(p.as_ref().to_path_buf(), 1, |p| { - (self.open)(&p) - })?; +where + Storage: AsRef<[u8]> + Send + Sync, +{ + fn act, F: FnOnce(&Zip) -> T>( + &self, + p: P, + cb: F, + ) -> Result { + let zip = self.lru.get_or_try_init(p.as_ref().to_path_buf(), 1, |p| (self.open)(&p))?; Ok(cb(zip.value())) } - fn file_type, S: AsRef>(&self, zip_path: P, p: S) -> Result { + fn file_type, S: AsRef>( + &self, + zip_path: P, + p: S, + ) -> Result { self.act(zip_path, |zip| zip.file_type(p.as_ref()))? } - fn read, S: AsRef>(&self, zip_path: P, p: S) -> Result, std::io::Error> { + fn read, S: AsRef>( + &self, + zip_path: P, + p: S, + ) -> Result, std::io::Error> { self.act(zip_path, |zip| zip.read(p.as_ref()))? } - fn read_to_string, S: AsRef>(&self, zip_path: P, p: S) -> Result { + fn read_to_string, S: AsRef>( + &self, + zip_path: P, + p: S, + ) -> Result { self.act(zip_path, |zip| zip.read_to_string(p.as_ref()))? } } @@ -167,31 +202,23 @@ fn vpath(p: &Path) -> std::io::Result { return Ok(VPath::Native(p.to_path_buf())); }; - let normalized_path - = crate::util::normalize_path(p_str); + let normalized_path = crate::util::normalize_path(p_str); // We remove potential leading slashes to avoid __virtual__ accidentally removing them - let normalized_relative_path - = normalized_path.strip_prefix('/') - .unwrap_or(&normalized_path); + let normalized_relative_path = normalized_path.strip_prefix('/').unwrap_or(&normalized_path); - let mut segment_it - = normalized_relative_path.split('/'); + let mut segment_it = normalized_relative_path.split('/'); // `split` returns [""] if the path is empty; we need to remove it if normalized_relative_path.is_empty() { segment_it.next(); } - let mut base_items: Vec<&str> - = Vec::new(); + let mut base_items: Vec<&str> = Vec::new(); - let mut virtual_items: Option> - = None; - let mut internal_items: Option> - = None; - let mut zip_items: Option> - = None; + let mut virtual_items: Option> = None; + let mut internal_items: Option> = None; + let mut zip_items: Option> = None; while let Some(segment) = segment_it.next() { if let Some(zip_segments) = &mut zip_items { @@ -200,8 +227,7 @@ fn vpath(p: &Path) -> std::io::Result { } if segment == "__virtual__" && virtual_items.is_none() { - let mut acc_segments - = Vec::with_capacity(3); + let mut acc_segments = Vec::with_capacity(3); acc_segments.push(segment); @@ -212,15 +238,14 @@ fn vpath(p: &Path) -> std::io::Result { // We retrieve the depth if let Some(depth_segment) = segment_it.next() { - let depth = depth_segment - .parse::(); + let depth = depth_segment.parse::(); acc_segments.push(depth_segment); // We extract the backward segments from the base ones if let Ok(depth) = depth { - let parent_segments = base_items - .split_off(base_items.len().saturating_sub(depth)); + let parent_segments = + base_items.split_off(base_items.len().saturating_sub(depth)); acc_segments.splice(0..0, parent_segments); } @@ -259,9 +284,7 @@ fn vpath(p: &Path) -> std::io::Result { Some((virtual_segments.join("/"), internal_segments.join("/"))) } - _ => { - None - }, + _ => None, }; if let Some(zip_segments) = zip_items { @@ -273,12 +296,9 @@ fn vpath(p: &Path) -> std::io::Result { })); } } - + if let Some(virtual_info) = virtual_info { - return Ok(VPath::Virtual(VirtualInfo { - base_path, - virtual_segments: virtual_info, - })); + return Ok(VPath::Virtual(VirtualInfo { base_path, virtual_segments: virtual_info })); } Ok(VPath::Native(PathBuf::from(base_path))) @@ -328,8 +348,10 @@ mod tests { #[test] fn test_zip_list() { - let zip = open_zip_via_read(&PathBuf::from("data/@babel-plugin-syntax-dynamic-import-npm-7.8.3-fb9ff5634a-8.zip")) - .unwrap(); + let zip = open_zip_via_read(&PathBuf::from( + "data/@babel-plugin-syntax-dynamic-import-npm-7.8.3-fb9ff5634a-8.zip", + )) + .unwrap(); let mut dirs: Vec<&String> = zip.dirs.iter().collect(); let mut files: Vec<&String> = zip.files.keys().collect(); @@ -337,30 +359,42 @@ mod tests { dirs.sort(); files.sort(); - assert_eq!(dirs, vec![ - "node_modules/", - "node_modules/@babel/", - "node_modules/@babel/plugin-syntax-dynamic-import/", - "node_modules/@babel/plugin-syntax-dynamic-import/lib/", - ]); - - assert_eq!(files, vec![ - "node_modules/@babel/plugin-syntax-dynamic-import/LICENSE", - "node_modules/@babel/plugin-syntax-dynamic-import/README.md", - "node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js", - "node_modules/@babel/plugin-syntax-dynamic-import/package.json", - ]); + assert_eq!( + dirs, + vec![ + "node_modules/", + "node_modules/@babel/", + "node_modules/@babel/plugin-syntax-dynamic-import/", + "node_modules/@babel/plugin-syntax-dynamic-import/lib/", + ] + ); + + assert_eq!( + files, + vec![ + "node_modules/@babel/plugin-syntax-dynamic-import/LICENSE", + "node_modules/@babel/plugin-syntax-dynamic-import/README.md", + "node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js", + "node_modules/@babel/plugin-syntax-dynamic-import/package.json", + ] + ); } #[test] fn test_zip_read() { - let zip = open_zip_via_read(&PathBuf::from("data/@babel-plugin-syntax-dynamic-import-npm-7.8.3-fb9ff5634a-8.zip")) - .unwrap(); + let zip = open_zip_via_read(&PathBuf::from( + "data/@babel-plugin-syntax-dynamic-import-npm-7.8.3-fb9ff5634a-8.zip", + )) + .unwrap(); - let res = zip.read_to_string("node_modules/@babel/plugin-syntax-dynamic-import/package.json") + let res = zip + .read_to_string("node_modules/@babel/plugin-syntax-dynamic-import/package.json") .unwrap(); - assert_eq!(res, "{\n \"name\": \"@babel/plugin-syntax-dynamic-import\",\n \"version\": \"7.8.3\",\n \"description\": \"Allow parsing of import()\",\n \"repository\": \"https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-dynamic-import\",\n \"license\": \"MIT\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"main\": \"lib/index.js\",\n \"keywords\": [\n \"babel-plugin\"\n ],\n \"dependencies\": {\n \"@babel/helper-plugin-utils\": \"^7.8.0\"\n },\n \"peerDependencies\": {\n \"@babel/core\": \"^7.0.0-0\"\n },\n \"devDependencies\": {\n \"@babel/core\": \"^7.8.0\"\n }\n}\n"); + assert_eq!( + res, + "{\n \"name\": \"@babel/plugin-syntax-dynamic-import\",\n \"version\": \"7.8.3\",\n \"description\": \"Allow parsing of import()\",\n \"repository\": \"https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-dynamic-import\",\n \"license\": \"MIT\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"main\": \"lib/index.js\",\n \"keywords\": [\n \"babel-plugin\"\n ],\n \"dependencies\": {\n \"@babel/helper-plugin-utils\": \"^7.8.0\"\n },\n \"peerDependencies\": {\n \"@babel/core\": \"^7.0.0-0\"\n },\n \"devDependencies\": {\n \"@babel/core\": \"^7.8.0\"\n }\n}\n" + ); } #[rstest] diff --git a/src/lib.rs b/src/lib.rs index 5017a7f..daffd89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,8 +8,11 @@ use fancy_regex::Regex; use indexmap::IndexMap; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, DefaultOnNull}; -use std::{path::{Path, PathBuf}, collections::{HashSet, HashMap, hash_map::Entry}}; +use serde_with::{DefaultOnNull, serde_as}; +use std::{ + collections::{HashMap, HashSet, hash_map::Entry}, + path::{Path, PathBuf}, +}; use util::RegexDef; #[derive(Clone, Debug, PartialEq, Serialize)] @@ -84,9 +87,7 @@ pub struct ResolutionHost { impl Default for ResolutionHost { fn default() -> ResolutionHost { - ResolutionHost { - find_pnp_manifest: Box::new(find_pnp_manifest), - } + ResolutionHost { find_pnp_manifest: Box::new(find_pnp_manifest) } } } @@ -169,8 +170,7 @@ pub struct Manifest { } fn parse_scoped_package_name(specifier: &str) -> Option<(String, Option)> { - let mut segments - = specifier.splitn(3, '/'); + let mut segments = specifier.splitn(3, '/'); let Some(scope) = segments.next() else { return None; @@ -180,28 +180,23 @@ fn parse_scoped_package_name(specifier: &str) -> Option<(String, Option) return None; }; - let package_name - = specifier[..scope.len() + name.len() + 1].to_string(); + let package_name = specifier[..scope.len() + name.len() + 1].to_string(); - let subpath - = segments.next().map(|v| v.to_string()); + let subpath = segments.next().map(|v| v.to_string()); Some((package_name, subpath)) } fn parse_global_package_name(specifier: &str) -> Option<(String, Option)> { - let mut segments - = specifier.splitn(2, '/'); + let mut segments = specifier.splitn(2, '/'); let Some(name) = segments.next() else { return None; }; - let package_name - = name.to_string(); + let package_name = name.to_string(); - let subpath - = segments.next().map(|v| v.to_string()); + let subpath = segments.next().map(|v| v.to_string()); Some((package_name, subpath)) } @@ -231,14 +226,20 @@ pub fn find_closest_pnp_manifest_path>(p: P) -> Option { } pub fn load_pnp_manifest>(p: P) -> Result { - let manifest_content = std::fs::read_to_string(p.as_ref()) - .map_err(|err| Error::FailedManifestHydration { - message: format!("We failed to read the content of the manifest.\n\nOriginal error: {}", err.to_string()), + let manifest_content = + std::fs::read_to_string(p.as_ref()).map_err(|err| Error::FailedManifestHydration { + message: format!( + "We failed to read the content of the manifest.\n\nOriginal error: {}", + err.to_string() + ), manifest_path: p.as_ref().to_path_buf(), })?; lazy_static! { - static ref RE: Regex = Regex::new("(const[ \\n]+RAW_RUNTIME_STATE[ \\n]*=[ \\n]*|hydrateRuntimeState\\(JSON\\.parse\\()'").unwrap(); + static ref RE: Regex = Regex::new( + "(const[ \\n]+RAW_RUNTIME_STATE[ \\n]*=[ \\n]*|hydrateRuntimeState\\(JSON\\.parse\\()'" + ) + .unwrap(); } let manifest_match = RE.find(&manifest_content) @@ -279,36 +280,33 @@ pub fn load_pnp_manifest>(p: P) -> Result { } pub fn init_pnp_manifest>(manifest: &mut Manifest, p: P) { - manifest.manifest_path = p.as_ref() - .to_path_buf(); + manifest.manifest_path = p.as_ref().to_path_buf(); - manifest.manifest_dir = p.as_ref().parent() - .expect("Should have a parent directory") - .to_owned(); + manifest.manifest_dir = p.as_ref().parent().expect("Should have a parent directory").to_owned(); for (name, ranges) in manifest.package_registry_data.iter_mut() { for (reference, info) in ranges.iter_mut() { - let package_location = manifest.manifest_dir - .join(info.package_location.clone()); + let package_location = manifest.manifest_dir.join(info.package_location.clone()); - let normalized_location = util::normalize_path( - &package_location.to_string_lossy(), - ); + let normalized_location = util::normalize_path(&package_location.to_string_lossy()); info.package_location = PathBuf::from(normalized_location); if !info.discard_from_lookup { - manifest.location_trie.insert(&info.package_location, PackageLocator { - name: name.clone(), - reference: reference.clone(), - }); + manifest.location_trie.insert( + &info.package_location, + PackageLocator { name: name.clone(), reference: reference.clone() }, + ); } } } - let top_level_pkg = manifest.package_registry_data - .get("").expect("Assertion failed: Should have a top-level name key") - .get("").expect("Assertion failed: Should have a top-level range key"); + let top_level_pkg = manifest + .package_registry_data + .get("") + .expect("Assertion failed: Should have a top-level name key") + .get("") + .expect("Assertion failed: Should have a top-level range key"); for (name, dependency) in &top_level_pkg.package_dependencies { if let Entry::Vacant(entry) = manifest.fallback_pool.entry(name.clone()) { @@ -325,25 +323,33 @@ pub fn is_dependency_tree_root<'a>(manifest: &'a Manifest, locator: &'a PackageL manifest.dependency_tree_roots.contains(locator) } -pub fn find_locator<'a, P: AsRef>(manifest: &'a Manifest, path: &P) -> Option<&'a PackageLocator> { +pub fn find_locator<'a, P: AsRef>( + manifest: &'a Manifest, + path: &P, +) -> Option<&'a PackageLocator> { let rel_path = pathdiff::diff_paths(path, &manifest.manifest_dir) .expect("Assertion failed: Provided path should be absolute"); if let Some(regex) = &manifest.ignore_pattern_data { if regex.0.is_match(&util::normalize_path(rel_path.to_string_lossy())).unwrap() { - return None + return None; } } manifest.location_trie.get_ancestor_value(&path) } -pub fn get_package<'a>(manifest: &'a Manifest, locator: &PackageLocator) -> Result<&'a PackageInformation, Error> { - let references = manifest.package_registry_data.get(&locator.name) +pub fn get_package<'a>( + manifest: &'a Manifest, + locator: &PackageLocator, +) -> Result<&'a PackageInformation, Error> { + let references = manifest + .package_registry_data + .get(&locator.name) .expect("Should have an entry in the package registry"); - let info = references.get(&locator.reference) - .expect("Should have an entry in the package registry"); + let info = + references.get(&locator.reference).expect("Should have an entry in the package registry"); Ok(info) } @@ -356,11 +362,18 @@ pub fn is_excluded_from_fallback(manifest: &Manifest, locator: &PackageLocator) } } -pub fn find_broken_peer_dependencies(_dependency: &str, _initial_package: &PackageLocator) -> Vec { +pub fn find_broken_peer_dependencies( + _dependency: &str, + _initial_package: &PackageLocator, +) -> Vec { vec![].to_vec() } -pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, specifier: &str, parent: P) -> Result { +pub fn resolve_to_unqualified_via_manifest>( + manifest: &Manifest, + specifier: &str, + parent: P, +) -> Result { let (ident, module_path) = parse_bare_identifier(specifier)?; if let Some(parent_locator) = find_locator(manifest, &parent) { @@ -368,7 +381,7 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, let mut reference_or_alias: Option = None; let mut is_set = false; - + if !is_set { if let Some(Some(binding)) = parent_pkg.package_dependencies.get(&ident) { reference_or_alias = Some(binding.clone()); @@ -376,7 +389,10 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, } } - if !is_set && manifest.enable_top_level_fallback && !is_excluded_from_fallback(manifest, parent_locator) { + if !is_set + && manifest.enable_top_level_fallback + && !is_excluded_from_fallback(manifest, parent_locator) + { if let Some(fallback_resolution) = manifest.fallback_pool.get(&ident) { reference_or_alias = fallback_resolution.clone(); is_set = true; @@ -389,7 +405,11 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, format!( "Your application tried to access {dependency_name}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since {dependency_name} isn't otherwise declared in your dependencies, this makes the require call ambiguous and unsound.\n\nRequired package: {dependency_name}{via}\nRequired by: ${issuer_path}", dependency_name = &ident, - via = if ident != specifier { format!(" (via \"{}\")", &specifier) } else { String::from("") }, + via = if ident != specifier { + format!(" (via \"{}\")", &specifier) + } else { + String::from("") + }, issuer_path = parent.as_ref().to_string_lossy(), ) } else { @@ -397,7 +417,11 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, "${issuer_locator_name} tried to access {dependency_name}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since {dependency_name} isn't otherwise declared in ${issuer_locator_name}'s dependencies, this makes the require call ambiguous and unsound.\n\nRequired package: {dependency_name}{via}\nRequired by: ${issuer_path}", issuer_locator_name = &parent_locator.name, dependency_name = &ident, - via = if ident != specifier { format!(" (via \"{}\")", &specifier) } else { String::from("") }, + via = if ident != specifier { + format!(" (via \"{}\")", &specifier) + } else { + String::from("") + }, issuer_path = parent.as_ref().to_string_lossy(), ) } @@ -406,7 +430,11 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, format!( "Your application tried to access {dependency_name}, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.\n\nRequired package: {dependency_name}{via}\nRequired by: {issuer_path}", dependency_name = &ident, - via = if ident != specifier { format!(" (via \"{}\")", &specifier) } else { String::from("") }, + via = if ident != specifier { + format!(" (via \"{}\")", &specifier) + } else { + String::from("") + }, issuer_path = parent.as_ref().to_string_lossy(), ) } else { @@ -415,7 +443,11 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, issuer_locator_name = &parent_locator.name, issuer_locator_reference = &parent_locator.reference, dependency_name = &ident, - via = if ident != specifier { format!(" (via \"{}\")", &specifier) } else { String::from("") }, + via = if ident != specifier { + format!(" (via \"{}\")", &specifier) + } else { + String::from("") + }, issuer_path = parent.as_ref().to_string_lossy(), ) } @@ -432,8 +464,12 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, if let Some(resolution) = reference_or_alias { let dependency_pkg = match resolution { - PackageDependency::Reference(reference) => get_package(manifest, &PackageLocator { name: ident, reference }), - PackageDependency::Alias(name, reference) => get_package(manifest, &PackageLocator { name, reference }), + PackageDependency::Reference(reference) => { + get_package(manifest, &PackageLocator { name: ident, reference }) + } + PackageDependency::Alias(name, reference) => { + get_package(manifest, &PackageLocator { name, reference }) + } }?; Ok(Resolution::Resolved(dependency_pkg.package_location.clone(), module_path)) @@ -444,16 +480,26 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, format!( "Your application tried to access {dependency_name} (a peer dependency); this isn't allowed as there is no ancestor to satisfy the requirement. Use a devDependency if needed.\n\nRequired package: {dependency_name}{via}\nRequired by: {issuer_path}", dependency_name = &ident, - via = if ident != specifier { format!(" (via \"{}\")", &specifier) } else { String::from("") }, + via = if ident != specifier { + format!(" (via \"{}\")", &specifier) + } else { + String::from("") + }, issuer_path = parent.as_ref().to_string_lossy(), ) - } else if !broken_ancestors.is_empty() && broken_ancestors.iter().all(|locator| is_dependency_tree_root(manifest, locator)) { + } else if !broken_ancestors.is_empty() + && broken_ancestors.iter().all(|locator| is_dependency_tree_root(manifest, locator)) + { format!( "{issuer_locator_name} tried to access {dependency_name} (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound.\n\nRequired package: {dependency_name}{via}\nRequired by: {issuer_locator_name}@{issuer_locator_reference} (via {issuer_path})", issuer_locator_name = &parent_locator.name, issuer_locator_reference = &parent_locator.reference, dependency_name = &ident, - via = if ident != specifier { format!(" (via \"{}\")", &specifier) } else { String::from("") }, + via = if ident != specifier { + format!(" (via \"{}\")", &specifier) + } else { + String::from("") + }, issuer_path = parent.as_ref().to_string_lossy(), ) } else { @@ -462,7 +508,11 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, issuer_locator_name = &parent_locator.name, issuer_locator_reference = &parent_locator.reference, dependency_name = &ident, - via = if ident != specifier { format!(" (via \"{}\")", &specifier) } else { String::from("") }, + via = if ident != specifier { + format!(" (via \"{}\")", &specifier) + } else { + String::from("") + }, issuer_path = parent.as_ref().to_string_lossy(), ) }; @@ -481,7 +531,11 @@ pub fn resolve_to_unqualified_via_manifest>(manifest: &Manifest, } } -pub fn resolve_to_unqualified>(specifier: &str, parent: P, config: &ResolutionConfig) -> Result { +pub fn resolve_to_unqualified>( + specifier: &str, + parent: P, + config: &ResolutionConfig, +) -> Result { if let Some(manifest) = (config.host.find_pnp_manifest)(parent.as_ref())? { resolve_to_unqualified_via_manifest(&manifest, specifier, &parent) } else { diff --git a/src/lib_tests.rs b/src/lib_tests.rs index e0b0a72..ea03591 100644 --- a/src/lib_tests.rs +++ b/src/lib_tests.rs @@ -22,8 +22,8 @@ mod tests { use super::*; use crate::{ - init_pnp_manifest, load_pnp_manifest, parse_bare_identifier, resolve_to_unqualified, - resolve_to_unqualified_via_manifest, ResolutionHost, + ResolutionHost, init_pnp_manifest, load_pnp_manifest, parse_bare_identifier, + resolve_to_unqualified, resolve_to_unqualified_via_manifest, }; #[test] @@ -35,10 +35,7 @@ mod tests { ..Default::default() }; - let config = ResolutionConfig { - host, - ..Default::default() - }; + let config = ResolutionConfig { host, ..Default::default() }; let resolution = resolve_to_unqualified( "lodash/cloneDeep", @@ -101,10 +98,7 @@ mod tests { ..Default::default() }; - let config = ResolutionConfig { - host, - ..Default::default() - }; + let config = ResolutionConfig { host, ..Default::default() }; let resolution = resolve_to_unqualified(specifier, parent, &config); @@ -126,9 +120,8 @@ mod tests { #[test] fn test_edge_case_one_pkg_cached_and_unplugged() { let manifest = { - let manifest_json_path = std::env::current_dir() - .unwrap() - .join("./data/edge_case_manifest_state.json"); + let manifest_json_path = + std::env::current_dir().unwrap().join("./data/edge_case_manifest_state.json"); let manifest_content = fs::read_to_string(&manifest_json_path).unwrap(); let mut manifest = serde_json::from_str::(&manifest_content).unwrap(); init_pnp_manifest(&mut manifest, manifest_json_path); @@ -167,18 +160,12 @@ mod tests { #[test] fn test_parse_package_name_with_long_subpath() { let parsed = parse_bare_identifier("pkg/a/b/c/index.js"); - assert_eq!( - parsed, - Ok(("pkg".to_string(), Some("a/b/c/index.js".to_string()))) - ); + assert_eq!(parsed, Ok(("pkg".to_string(), Some("a/b/c/index.js".to_string())))); } #[test] fn test_parse_scoped_package_with_long_subpath() { let parsed = parse_bare_identifier("@scope/pkg/a/b/c/index.js"); - assert_eq!( - parsed, - Ok(("@scope/pkg".to_string(), Some("a/b/c/index.js".to_string()))) - ); + assert_eq!(parsed, Ok(("@scope/pkg".to_string(), Some("a/b/c/index.js".to_string())))); } } diff --git a/src/main.rs b/src/main.rs index 7ea5690..e85552e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use pnp::{ResolutionConfig, Resolution}; +use pnp::{Resolution, ResolutionConfig}; use std::path::PathBuf; fn main() { @@ -7,31 +7,28 @@ fn main() { // Skip the program name args.next(); - let specifier = args.next() - .expect("A specifier must be provided"); + let specifier = args.next().expect("A specifier must be provided"); - let parent = args.next() - .map(PathBuf::from) - .expect("A parent url must be provided"); + let parent = args.next().map(PathBuf::from).expect("A parent url must be provided"); println!("specifier = {}", specifier); println!("parent = {:?}", parent); - let resolution = pnp::resolve_to_unqualified(&specifier, &parent, &ResolutionConfig { - ..Default::default() - }); + let resolution = pnp::resolve_to_unqualified( + &specifier, + &parent, + &ResolutionConfig { ..Default::default() }, + ); match resolution { - Ok(res) => { - match res { - Resolution::Resolved(p, subpath) => { - println!("result = Package ({:?}, {:?})", p, subpath); - } - Resolution::Skipped => { - println!("result = Skipped"); - } + Ok(res) => match res { + Resolution::Resolved(p, subpath) => { + println!("result = Package ({:?}, {:?})", p, subpath); } - } + Resolution::Skipped => { + println!("result = Skipped"); + } + }, Err(err) => { println!("{}", err.to_string()); } diff --git a/src/util.rs b/src/util.rs index 9b0d438..d5ecde2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,9 +1,9 @@ use fancy_regex::Regex; -use serde::{de::Error, Deserialize, Deserializer}; +use serde::{Deserialize, Deserializer, de::Error}; use std::borrow::Cow; use path_slash::PathBufExt; -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; #[derive(Debug, Default, Clone)] pub struct Trie { @@ -37,9 +37,7 @@ pub fn normalize_path>(original: P) -> String { let original_str = original.as_ref(); let p = PathBuf::from(original_str); - let mut str = clean_path::clean(p) - .to_slash_lossy() - .to_string(); + let mut str = clean_path::clean(p).to_slash_lossy().to_string(); if original_str.ends_with('/') && !str.ends_with('/') { str.push('/'); @@ -100,7 +98,8 @@ pub struct RegexDef(pub Regex); impl<'de> Deserialize<'de> for RegexDef { fn deserialize(d: D) -> Result - where D: Deserializer<'de>, + where + D: Deserializer<'de>, { let s = >::deserialize(d)?; diff --git a/src/zip.rs b/src/zip.rs index 40a669e..368cad5 100644 --- a/src/zip.rs +++ b/src/zip.rs @@ -1,7 +1,7 @@ +use byteorder::{LittleEndian, ReadBytesExt}; use std::collections::{HashMap, HashSet}; -use std::io::Cursor; use std::error::Error; -use byteorder::{ReadBytesExt, LittleEndian}; +use std::io::Cursor; use std::io::Read; use crate::fs::FileType; @@ -21,20 +21,21 @@ pub struct Entry { } #[derive(Debug)] -pub struct Zip where T : AsRef<[u8]> { +pub struct Zip +where + T: AsRef<[u8]>, +{ storage: T, pub files: HashMap, pub dirs: HashSet, } impl Zip -where T : AsRef<[u8]> { +where + T: AsRef<[u8]>, +{ pub fn new(storage: T) -> Result, Box> { - let mut zip = Zip { - storage, - files: Default::default(), - dirs: Default::default(), - }; + let mut zip = Zip { storage, files: Default::default(), dirs: Default::default() }; for (name, maybe_entry) in list_zip_entries(zip.storage.as_ref())? { let name = util::normalize_path(name); @@ -74,23 +75,22 @@ where T : AsRef<[u8]> { } pub fn read(&self, p: &str) -> Result, std::io::Error> { - let entry = self.files.get(p) - .ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?; + let entry = self.files.get(p).ok_or(std::io::Error::from(std::io::ErrorKind::NotFound))?; let data = self.storage.as_ref(); let slice = &data[entry.offset..entry.offset + entry.size]; match entry.compression { Compression::Deflate => { - let decompressed_data = miniz_oxide::inflate::decompress_to_vec(&slice) - .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Error during decompression"))?; + let decompressed_data = + miniz_oxide::inflate::decompress_to_vec(&slice).map_err(|_| { + std::io::Error::new(std::io::ErrorKind::Other, "Error during decompression") + })?; Ok(decompressed_data) } - Compression::Uncompressed => { - Ok(slice.to_vec()) - } + Compression::Uncompressed => Ok(slice.to_vec()), } } @@ -102,15 +102,11 @@ where T : AsRef<[u8]> { } fn io_bytes_to_str(vec: &[u8]) -> Result<&str, std::io::Error> { - std::str::from_utf8(vec) - .map_err(|_| make_io_utf8_error()) + std::str::from_utf8(vec).map_err(|_| make_io_utf8_error()) } fn make_io_utf8_error() -> std::io::Error { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - "File did not contain valid UTF-8" - ) + std::io::Error::new(std::io::ErrorKind::InvalidData, "File did not contain valid UTF-8") } pub fn list_zip_entries(data: &[u8]) -> Result>, Box> { @@ -144,7 +140,9 @@ fn find_central_directory_offset(cursor: &mut Cursor<&[u8]>) -> Result) -> Result)>, Box> { +fn read_central_file_header( + cursor: &mut Cursor<&[u8]>, +) -> Result)>, Box> { let signature = cursor.read_u32::()?; if signature != 0x02014b50 { return Ok(None); @@ -160,7 +158,8 @@ fn read_central_file_header(cursor: &mut Cursor<&[u8]>) -> Result Ok(Compression::Uncompressed), 8 => Ok(Compression::Deflate), _ => Err("Oh no"), - }.unwrap(); + } + .unwrap(); let _crc32 = cursor.read_u32::()?; let compressed_size = cursor.read_u32::()? as u64; @@ -188,9 +187,14 @@ fn read_central_file_header(cursor: &mut Cursor<&[u8]>) -> Result()? as usize; - let local_file_header_extra_field_length = local_file_header_cursor.read_u16::()? as usize; - let file_data_offset = local_header_offset + 30 + local_file_header_file_name_length as u64 + local_file_header_extra_field_length as u64; + let local_file_header_file_name_length = + local_file_header_cursor.read_u16::()? as usize; + let local_file_header_extra_field_length = + local_file_header_cursor.read_u16::()? as usize; + let file_data_offset = local_header_offset + + 30 + + local_file_header_file_name_length as u64 + + local_file_header_extra_field_length as u64; let entry = Entry { compression,