Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Scripter17 committed Feb 25, 2024
1 parent a4e59e4 commit f876009
Show file tree
Hide file tree
Showing 9 changed files with 482 additions and 304 deletions.
286 changes: 160 additions & 126 deletions src/rules/conditions.rs

Large diffs are not rendered by default.

99 changes: 50 additions & 49 deletions src/rules/mappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::collections::hash_set::HashSet;
#[cfg(all(feature = "http", not(target_family = "wasm")))]
use reqwest::{self, Error as ReqwestError, header::HeaderMap};

use crate::glue::{self, string_or_struct, optional_string_or_struct};
use crate::glue::*;
use crate::types::*;

/// The part of a [`crate::rules::Rule`] that specifies how to modify a [`Url`] if the rule's condition passes.
Expand Down Expand Up @@ -191,7 +191,7 @@ pub enum Mapper {
/// Removes the path segments with an index in the specified list.
/// See [`Url::path_segments`] for details.
/// # Errors
/// If the URL cannot be a base, returns the error [`MapperError::UrlCannotBeABase`].
/// If the URL cannot be a base, returns the error [`MapperError::UrlDoesNotHaveAPath`].
/// # Examples
/// ```
/// # use url_cleaner::rules::*;
Expand All @@ -212,12 +212,12 @@ pub enum Mapper {

/// Sets the specified URL part to `to`.
/// # Errors
/// If `to` is `None` and `part` cannot be `None` (see [`UrlPart`] for details), returns the error [`types::PartError::PartCannotBeNone`].
/// If `to` is `None` and `part` cannot be `None` (see [`UrlPart`] for details), returns the error [`SetPartError::PartCannotBeNone`].
#[cfg(feature = "string-source")]
SetPart {
/// The name of the part to replace.
part: UrlPart,
/// If the relevant [`Url`] part getter returns [`None`], this decides whether to return a [`super::conditions::ConditionError::UrlPartNotFound`] or pretend it's just an empty string and check that.
/// Decides if `part`'s call to [`UrlPart::get`] should return `Some("")` instead of `None`.
/// Defaults to `true`.
#[serde(default = "get_true")]
none_to_empty_string: bool,
Expand All @@ -229,7 +229,7 @@ pub enum Mapper {
SetPart {
/// The name of the part to replace.
part: UrlPart,
/// If the relevant [`Url`] part getter returns [`None`], this decides whether to return a [`super::conditions::ConditionError::UrlPartNotFound`] or pretend it's just an empty string and check that.
/// Decides if `part`'s call to [`UrlPart::get`] should return `Some("")` instead of `None`.
/// Defaults to `true`.
#[serde(default = "get_true")]
none_to_empty_string: bool,
Expand All @@ -239,12 +239,12 @@ pub enum Mapper {
/// Modifies the specified part of the URL.
/// # Errors
/// If `how` is `StringModification::ReplaceAt` and the specified range is either out of bounds or not on UTF-8 boundaries, returns the error [`MapperError::StringError`].
/// If the modification fails, returns the error [`MapperError::PartError`].
/// If the modification fails, returns the error [`MapperError::PartModificationError`].
#[cfg(feature = "string-modification")]
ModifyPart {
/// The name of the part to modify.
part: UrlPart,
/// If the relevant [`Url`] part getter returns [`None`], this decides whether to return a [`super::conditions::ConditionError::UrlPartNotFound`] or pretend it's just an empty string and check that.
/// Decides if `part`'s call to [`UrlPart::get`] should return `Some("")` instead of `None`.
/// Defaults to `true`.
#[serde(default = "get_true")]
none_to_empty_string: bool,
Expand All @@ -253,11 +253,11 @@ pub enum Mapper {
},
/// Copies the part specified by `from` to the part specified by `to`.
/// # Errors
/// If the part specified by `from` is None, `none_to_empty_string` is `false`, and the part specified by `to` cannot be `None` (see [`Mapper::SetPart`]), returns the error [`types::PartError::PartCannotBeNone`].
/// If the part specified by `from` is None, `none_to_empty_string` is `false`, and the part specified by `to` cannot be `None` (see [`Mapper::SetPart`]), returns the error [`SetPartError::PartCannotBeNone`].
CopyPart {
/// The part to get the value from.
from: UrlPart,
/// If the relevant [`Url`] part getter returns [`None`], this decides whether to return a [`super::conditions::ConditionError::UrlPartNotFound`] or pretend it's just an empty string and check that.
/// Decides if `from`'s call to [`UrlPart::get`] should return `Some("")` instead of `None`.
/// Defaults to `true`.
#[serde(default = "get_true")]
none_to_empty_string: bool,
Expand All @@ -273,13 +273,13 @@ pub enum Mapper {
RegexSubUrlPart {
/// The name of the part to modify.
part: UrlPart,
/// If the relevant [`Url`] part getter returns [`None`], this decides whether to return a [`super::conditions::ConditionError::UrlPartNotFound`] or pretend it's just an empty string and check that.
/// Decides if `part`'s call to [`UrlPart::get`] should return `Some("")` instead of `None`.
/// Defaults to `true`.
#[serde(default = "get_true")]
none_to_empty_string: bool,
/// The regex that is used to match and extract parts of the selected part.
#[serde(deserialize_with = "string_or_struct")]
regex: glue::RegexWrapper,
regex: RegexWrapper,
/// The pattern the extracted parts are put into.
/// See [`regex::Regex::replace`] for details.
#[serde(deserialize_with = "string_or_struct", default = "eufp_expand")]
Expand All @@ -289,13 +289,13 @@ pub enum Mapper {
RegexSubUrlPart {
/// The name of the part to modify.
part: UrlPart,
/// If the relevant [`Url`] part getter returns [`None`], this decides whether to return a [`super::conditions::ConditionError::UrlPartNotFound`] or pretend it's just an empty string and check that.
/// Decides if `part`'s call to [`UrlPart::get`] should return `Some("")` instead of `None`.
/// Defaults to `true`.
#[serde(default = "get_true")]
none_to_empty_string: bool,
/// The regex that is used to match and extract parts of the selected part.
#[serde(deserialize_with = "string_or_struct")]
regex: glue::RegexWrapper,
regex: RegexWrapper,
/// The pattern the extracted parts are put into.
/// See [`regex::Regex::replace`] for details.
#[serde(default = "efup_expand")]
Expand Down Expand Up @@ -325,18 +325,18 @@ pub enum Mapper {
#[cfg(all(feature = "http", not(target_family = "wasm")))]
ExpandShortLink {
/// The headers to send alongside the param's default headers.
#[serde(default, with = "crate::glue::headermap")]
#[serde(default, with = "headermap")]
headers: HeaderMap
},
/// Gets the URL as a webpage, uses `regex` to find a URL, and uses `expand` to join the regex capture's groups.
#[cfg(all(feature = "http", feature = "regex", not(target_family = "wasm"), feature = "string-source"))]
ExtractUrlFromPage {
/// The headers to send alongside the param's default headers.
#[serde(default, with = "crate::glue::headermap")]
#[serde(default, with = "headermap")]
headers: HeaderMap,
/// The pattern to search for in the page.
#[serde(deserialize_with = "string_or_struct")]
regex: glue::RegexWrapper,
regex: RegexWrapper,
/// Used for [`regex::Captures::expand`].
/// Defaults to `"$1"`.
#[serde(deserialize_with = "string_or_struct", default = "eufp_expand")]
Expand All @@ -345,22 +345,22 @@ pub enum Mapper {
#[cfg(all(feature = "http", feature = "regex", not(target_family = "wasm"), not(feature = "string-source")))]
ExtractUrlFromPage {
/// The headers to send alongside the param's default headers.
#[serde(default, with = "crate::glue::headermap")]
#[serde(default, with = "headermap")]
headers: HeaderMap,
/// The pattern to search for in the page.
#[serde(deserialize_with = "string_or_struct")]
regex: glue::RegexWrapper,
/// Used for [`regex::Captures::expand`].
regex: RegexWrapper,
/// The substitution for use in [`regex::Captures::expand`].
/// Defaults to `"$1"`.
#[serde(default = "efup_expand")]
expand: String
},
/// Execute a command and sets the URL to its output. Any argument parameter with the value `"{}"` is replaced with the URL. If the command STDOUT ends in a newline it is stripped.
/// Useful when what you want to do is really specific and niche.
/// # Errors
/// Returns the error [`glue::CommandError`] if the command fails.
/// Returns the error [`CommandError`] if the command fails.
#[cfg(feature = "commands")]
ReplaceWithCommandOutput(glue::CommandWrapper)
ReplaceWithCommandOutput(CommandWrapper)
}

const fn get_true() -> bool {true}
Expand All @@ -372,63 +372,64 @@ fn eufp_expand() -> String {"$1".to_string()}
/// An enum of all possible errors a [`Mapper`] can return.
#[derive(Error, Debug)]
pub enum MapperError {
/// The [`Mapper::Error`] mapper always returns this error.
/// Returned when [`Mapper::Error`] is used.
#[error("Mapper::Error was used.")]
ExplicitError,
/// Returned when the mapper has `none_to_empty_string` set to `false` and the requested part of the provided URL is `None`.
/// Returned when a call to [`UrlPart::get`] returns `None` where it has to return `Some`.
#[error("The provided URL does not have the requested part.")]
UrlPartNotFound,
/// Returned when the provided URL's query does not contain a query parameter with the requested name.
#[error("The URL provided does not contain the query parameter required.")]
/// Returned when the provided URL does not contain the requested query parameter.
#[error("The provided URL does not contain the requested query parameter.")]
CannotFindQueryParam,
/// Returned when the would-be new URL could not be parsed by [`url::Url`].
/// Returned when a [`ParseError`] is encountered.
#[error(transparent)]
UrlParseError(#[from] ParseError),
/// Returned when an HTTP request fails. Currently only applies to the Expand301 mapper.
/// Returned when a [`ReqwestError`] is encountered.
#[cfg(all(feature = "http", not(target_family = "wasm")))]
#[error(transparent)]
ReqwestError(#[from] ReqwestError),
/// Returned when an I/O error occurs. Currently only applies when Expand301 is set to cache redirects.
/// Returned when an [`IoError`] is encountered.
#[cfg(feature = "cache-redirects")]
#[error(transparent)]
IoError(#[from] IoError),
/// UTF-8 error.
/// Returned when a [`Utf8Error`] is encountered.
#[error(transparent)]
Utf8Error(#[from] Utf8Error),
/// The command failed.
/// Returned when a [`CommandError`] is encountered.
#[cfg(feature = "commands")]
#[error(transparent)]
CommandError(#[from] glue::CommandError),
/// A string operation failed.
CommandError(#[from] CommandError),
/// Returned when a [`StringError`] is encountered.
#[error(transparent)]
StringError(#[from] StringError),
/// The part modification failed.
/// Returned when a [`PartModificationError`] is encountered.
#[cfg(feature = "string-modification")]
#[error(transparent)]
PartModificationError(#[from] PartModificationError),
/// Returned when a [`SetPartError`] is encountered.
#[error(transparent)]
SetPartError(#[from] SetPartError),
/// The URL cannot be a base.
#[error("The URL cannot be a base.")]
UrlCannotBeABase,
/// An instance of the regex pattern could not be found in the page returned by the URL.
#[error("An instance of the regex pattern could not be found in the page returned by the URL.")]
PatternNotFound,
/// A variable was requested but not found at runtime.
/// Returned when the provided URL does not have a path.
#[error("The URL does not have a path.")]
UrlDoesNotHaveAPath,
/// Returned when a regex does not find any matches.
#[error("A regex pattern did not find any matches.")]
NoRegexMatchesFound,
/// Returned when the requested variable is not found in [`crate::config::Params::vars`].
#[error("A variable was requested but not found at runtime.")]
VarNotFound,
/// The specified [`StringSource`] returned `None`.
#[error("The specified StringSource returned None.")]
/// Returned when a call to [`StringSource::get`] returns `None` where it has to be `Some`.
#[error("The specified StringSource returned None where it had to be Some.")]
StringSourceIsNone,
/// The call to [`StringMatcher::satisfied_by`] returned an error.
/// Returned when a [`StringMatcherError`] is encountered.
#[cfg(feature = "string-matcher")]
#[error(transparent)]
StringMatcherError(#[from] StringMatcherError),
/// The call to [`StringSource::get`] returned an error.
/// Returned when a [`StringSourceError`] is encountered.
#[cfg(feature = "string-source")]
#[error(transparent)]
StringSourceError(#[from] StringSourceError),
/// The call to [`StringModification::apply`] returned an error.
/// Returned when a [`StringModificationError`] is encountered.
#[cfg(feature = "string-modification")]
#[error(transparent)]
StringModificationError(#[from] StringModificationError)
Expand Down Expand Up @@ -495,7 +496,7 @@ impl Mapper {
Self::RemoveQueryParamsMatching(matcher) => {
let mut new_query=form_urlencoded::Serializer::new(String::new());
for (name, value) in url.query_pairs() {
if !matcher.satisfied_by(&name, params)? {
if !matcher.satisfied_by(&name, url, params)? {
new_query.append_pair(&name, &value);
}
}
Expand All @@ -506,7 +507,7 @@ impl Mapper {
Self::AllowQueryParamsMatching(matcher) => {
let mut new_query=form_urlencoded::Serializer::new(String::new());
for (name, value) in url.query_pairs() {
if matcher.satisfied_by(&name, params)? {
if matcher.satisfied_by(&name, url, params)? {
new_query.append_pair(&name, &value);
}
}
Expand All @@ -529,7 +530,7 @@ impl Mapper {
// Other parts

Self::SetHost(new_host) => url.set_host(Some(new_host))?,
Self::RemovePathSegments(indices) => url.set_path(&url.path_segments().ok_or(MapperError::UrlCannotBeABase)?.enumerate().filter_map(|(i, x)| (!indices.contains(&i)).then_some(x)).collect::<Vec<_>>().join("/")),
Self::RemovePathSegments(indices) => url.set_path(&url.path_segments().ok_or(MapperError::UrlDoesNotHaveAPath)?.enumerate().filter_map(|(i, x)| (!indices.contains(&i)).then_some(x)).collect::<Vec<_>>().join("/")),
#[cfg(feature = "string-source")]
Self::Join(with) => if let Some(value) = with.get(url, params, false)? {
*url=url.join(&value)?;
Expand Down Expand Up @@ -592,7 +593,7 @@ impl Mapper {
#[cfg(all(feature = "http", feature = "regex", not(target_family = "wasm")))]
Self::ExtractUrlFromPage{headers, regex, expand} => if let Some(expand) = expand.get(url, params, false)? {
let mut ret = String::new();
regex.captures(&params.http_client()?.get(url.as_str()).headers(headers.clone()).send()?.text()?).ok_or(MapperError::PatternNotFound)?.expand(&expand, &mut ret);
regex.captures(&params.http_client()?.get(url.as_str()).headers(headers.clone()).send()?.text()?).ok_or(MapperError::NoRegexMatchesFound)?.expand(&expand, &mut ret);
*url=Url::parse(&ret)?;
} else {
Err(MapperError::StringSourceIsNone)?
Expand Down
Loading

0 comments on commit f876009

Please sign in to comment.