From 1de218a78a1d91d6e65f0bba8306e8e50d6a86be Mon Sep 17 00:00:00 2001 From: Thomas Zahner Date: Thu, 10 Jul 2025 14:35:50 +0200 Subject: [PATCH] Unwrap option type --- examples/collect_links/collect_links.rs | 16 ++--- lychee-bin/src/options.rs | 15 ++--- lychee-lib/src/collector.rs | 80 ++++++++++--------------- lychee-lib/src/types/input.rs | 26 ++++---- 4 files changed, 59 insertions(+), 78 deletions(-) diff --git a/examples/collect_links/collect_links.rs b/examples/collect_links/collect_links.rs index 57edd5f..9299c94 100644 --- a/examples/collect_links/collect_links.rs +++ b/examples/collect_links/collect_links.rs @@ -7,18 +7,10 @@ use tokio_stream::StreamExt; async fn main() -> Result<()> { // Collect all links from the following inputs let inputs = vec![ - Input { - source: InputSource::RemoteUrl(Box::new( - Url::parse("https://github.com/lycheeverse/lychee").unwrap(), - )), - file_type_hint: None, - excluded_paths: None, - }, - Input { - source: InputSource::FsPath(PathBuf::from("fixtures/TEST.md")), - file_type_hint: None, - excluded_paths: None, - }, + Input::from_input_source(InputSource::RemoteUrl(Box::new( + Url::parse("https://github.com/lycheeverse/lychee").unwrap(), + ))), + Input::from_input_source(InputSource::FsPath(PathBuf::from("fixtures/TEST.md"))), ]; let links = Collector::default() diff --git a/lychee-bin/src/options.rs b/lychee-bin/src/options.rs index 924d0c7..e53639f 100644 --- a/lychee-bin/src/options.rs +++ b/lychee-bin/src/options.rs @@ -331,15 +331,16 @@ impl LycheeOptions { // accept a `Vec` in `LycheeOptions` and do the conversion there, but // we wouldn't get access to `glob_ignore_case`. pub(crate) fn inputs(&self) -> Result> { - let excluded = if self.config.exclude_path.is_empty() { - None - } else { - Some(self.config.exclude_path.clone()) - }; - self.raw_inputs .iter() - .map(|s| Input::new(s, None, self.config.glob_ignore_case, excluded.clone())) + .map(|s| { + Input::new( + s, + None, + self.config.glob_ignore_case, + self.config.exclude_path.clone(), + ) + }) .collect::>() .context("Cannot parse inputs from arguments") } diff --git a/lychee-lib/src/collector.rs b/lychee-lib/src/collector.rs index 8ce6861..c3db7ff 100644 --- a/lychee-lib/src/collector.rs +++ b/lychee-lib/src/collector.rs @@ -274,7 +274,12 @@ mod tests { // Treat as plaintext file (no extension) let file_path = temp_dir.path().join("README"); let _file = File::create(&file_path).unwrap(); - let input = Input::new(&file_path.as_path().display().to_string(), None, true, None)?; + let input = Input::new( + &file_path.as_path().display().to_string(), + None, + true, + vec![], + )?; let contents: Vec<_> = input .get_contents( true, @@ -293,7 +298,7 @@ mod tests { #[tokio::test] async fn test_url_without_extension_is_html() -> Result<()> { - let input = Input::new("https://example.com/", None, true, None)?; + let input = Input::new("https://example.com/", None, true, vec![])?; let contents: Vec<_> = input .get_contents( true, @@ -330,33 +335,17 @@ mod tests { let mock_server = mock_server!(StatusCode::OK, set_body_string(TEST_URL)); let inputs = vec![ - Input { - source: InputSource::String(TEST_STRING.to_owned()), - file_type_hint: None, - excluded_paths: None, - }, - Input { - source: InputSource::RemoteUrl(Box::new( - Url::parse(&mock_server.uri()) - .map_err(|e| (mock_server.uri(), e)) - .unwrap(), - )), - file_type_hint: None, - excluded_paths: None, - }, - Input { - source: InputSource::FsPath(file_path), - file_type_hint: None, - excluded_paths: None, - }, - Input { - source: InputSource::FsGlob { - pattern: temp_dir_path.join("glob*").to_str().unwrap().to_owned(), - ignore_case: true, - }, - file_type_hint: None, - excluded_paths: None, - }, + Input::from_input_source(InputSource::String(TEST_STRING.to_owned())), + Input::from_input_source(InputSource::RemoteUrl(Box::new( + Url::parse(&mock_server.uri()) + .map_err(|e| (mock_server.uri(), e)) + .unwrap(), + ))), + Input::from_input_source(InputSource::FsPath(file_path)), + Input::from_input_source(InputSource::FsGlob { + pattern: temp_dir_path.join("glob*").to_str().unwrap().to_owned(), + ignore_case: true, + }), ]; let links = collect_verbatim(inputs, None, None, FileType::default_extensions()) @@ -383,7 +372,7 @@ mod tests { let input = Input { source: InputSource::String("This is [a test](https://endler.dev). This is a relative link test [Relative Link Test](relative_link)".to_string()), file_type_hint: Some(FileType::Markdown), - excluded_paths: None, + excluded_paths: vec![], }; let links = collect(vec![input], None, Some(base)).await.ok().unwrap(); @@ -409,7 +398,7 @@ mod tests { .to_string(), ), file_type_hint: Some(FileType::Html), - excluded_paths: None, + excluded_paths: vec![], }; let links = collect(vec![input], None, Some(base)).await.ok().unwrap(); @@ -438,7 +427,7 @@ mod tests { .to_string(), ), file_type_hint: Some(FileType::Html), - excluded_paths: None, + excluded_paths: vec![], }; let links = collect(vec![input], None, Some(base)).await.ok().unwrap(); @@ -464,7 +453,7 @@ mod tests { .to_string(), ), file_type_hint: Some(FileType::Markdown), - excluded_paths: None, + excluded_paths: vec![], }; let links = collect(vec![input], None, Some(base)).await.ok().unwrap(); @@ -487,7 +476,7 @@ mod tests { let input = Input { source: InputSource::String(input), file_type_hint: Some(FileType::Html), - excluded_paths: None, + excluded_paths: vec![], }; let links = collect(vec![input], None, Some(base)).await.ok().unwrap(); @@ -516,11 +505,7 @@ mod tests { let server_uri = Url::parse(&mock_server.uri()).unwrap(); - let input = Input { - source: InputSource::RemoteUrl(Box::new(server_uri.clone())), - file_type_hint: None, - excluded_paths: None, - }; + let input = Input::from_input_source(InputSource::RemoteUrl(Box::new(server_uri.clone()))); let links = collect(vec![input], None, None).await.ok().unwrap(); @@ -534,13 +519,10 @@ mod tests { #[tokio::test] async fn test_email_with_query_params() { - let input = Input { - source: InputSource::String( - "This is a mailto:user@example.com?subject=Hello link".to_string(), - ), - file_type_hint: None, - excluded_paths: None, - }; + let input = Input::from_input_source(InputSource::String( + "This is a mailto:user@example.com?subject=Hello link".to_string(), + )); + let links = collect(vec![input], None, None).await.ok().unwrap(); let expected_links = HashSet::from_iter([mail("user@example.com")]); @@ -569,7 +551,7 @@ mod tests { .unwrap(), )), file_type_hint: Some(FileType::Html), - excluded_paths: None, + excluded_paths: vec![], }, Input { source: InputSource::RemoteUrl(Box::new( @@ -580,7 +562,7 @@ mod tests { .unwrap(), )), file_type_hint: Some(FileType::Html), - excluded_paths: None, + excluded_paths: vec![], }, ]; @@ -615,7 +597,7 @@ mod tests { .into(), ), file_type_hint: Some(FileType::Html), - excluded_paths: None, + excluded_paths: vec![], }; let links = collect(vec![input], None, Some(base)).await.ok().unwrap(); diff --git a/lychee-lib/src/types/input.rs b/lychee-lib/src/types/input.rs index 6665085..42ea761 100644 --- a/lychee-lib/src/types/input.rs +++ b/lychee-lib/src/types/input.rs @@ -108,7 +108,7 @@ pub struct Input { /// Hint to indicate which extractor to use pub file_type_hint: Option, /// Excluded paths that will be skipped when reading content - pub excluded_paths: Option>, + pub excluded_paths: Vec, } impl Input { @@ -124,7 +124,7 @@ impl Input { value: &str, file_type_hint: Option, glob_ignore_case: bool, - excluded_paths: Option>, + excluded_paths: Vec, ) -> Result { let source = if value == STDIN { InputSource::Stdin @@ -200,7 +200,16 @@ impl Input { /// Returns an error if the input does not exist (i.e. invalid path) /// and the input cannot be parsed as a URL. pub fn from_value(value: &str) -> Result { - Self::new(value, None, false, None) + Self::new(value, None, false, vec![]) + } + + /// Convenience constructor + pub fn from_input_source(source: InputSource) -> Self { + Self { + source, + file_type_hint: None, + excluded_paths: vec![], + } } /// Retrieve the contents from the input @@ -360,10 +369,7 @@ impl Input { /// Check if the given path was excluded from link checking fn is_excluded_path(&self, path: &PathBuf) -> bool { - let Some(excluded_paths) = &self.excluded_paths else { - return false; - }; - is_excluded_path(excluded_paths, path) + is_excluded_path(&self.excluded_paths, path) } /// Get the input content of a given path @@ -437,15 +443,15 @@ mod tests { assert!(path.exists()); assert!(path.is_relative()); - let input = Input::new(test_file, None, false, None); + let input = Input::new(test_file, None, false, vec![]); assert!(input.is_ok()); assert!(matches!( input, Ok(Input { source: InputSource::FsPath(PathBuf { .. }), file_type_hint: None, - excluded_paths: None, - }) + excluded_paths + }) if excluded_paths.is_empty() )); }