better project structure
This commit is contained in:
38
src/shared/slug.rs
Normal file
38
src/shared/slug.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
//! URL slug helpers shared by the catalog admin (products and categories).
|
||||
|
||||
use loco_rs::prelude::*;
|
||||
|
||||
/// Lowercase a string and collapse every run of non-alphanumeric characters
|
||||
/// into a single dash, trimming dashes from the ends.
|
||||
pub fn slugify(value: &str) -> String {
|
||||
let mut slug = String::new();
|
||||
let mut last_was_dash = false;
|
||||
for ch in value.chars().flat_map(char::to_lowercase) {
|
||||
if ch.is_ascii_alphanumeric() {
|
||||
slug.push(ch);
|
||||
last_was_dash = false;
|
||||
} else if !last_was_dash && !slug.is_empty() {
|
||||
slug.push('-');
|
||||
last_was_dash = true;
|
||||
}
|
||||
}
|
||||
slug.trim_matches('-').to_string()
|
||||
}
|
||||
|
||||
/// Find the first slug that does not already exist, appending `-2`, `-3`, … to
|
||||
/// `base` until `exists` reports the candidate as free. An empty `base` falls
|
||||
/// back to `"item"`.
|
||||
pub async fn unique_slug<F, Fut>(base: &str, mut exists: F) -> Result<String>
|
||||
where
|
||||
F: FnMut(String) -> Fut,
|
||||
Fut: std::future::Future<Output = Result<bool>>,
|
||||
{
|
||||
let base = if base.is_empty() { "item" } else { base };
|
||||
let mut slug = base.to_string();
|
||||
let mut suffix = 2;
|
||||
while exists(slug.clone()).await? {
|
||||
slug = format!("{base}-{suffix}");
|
||||
suffix += 1;
|
||||
}
|
||||
Ok(slug)
|
||||
}
|
||||
Reference in New Issue
Block a user