Extiende normalización de cadenas ASCII

This commit is contained in:
Manuel Cillero 2026-01-04 19:14:51 +01:00
parent e9d326cd99
commit cf7aba2b53
3 changed files with 70 additions and 25 deletions

View file

@ -1,4 +1,4 @@
use crate::{builder_fn, trace, util, AutoDefault};
use crate::{builder_fn, util, AutoDefault};
use std::borrow::Cow;
use std::collections::HashSet;
@ -74,16 +74,10 @@ impl Classes {
/// lista de clases actual.
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
let normalized = match util::normalize_ascii(classes.as_ref()) {
Ok(c) => c,
Err(util::NormalizeAsciiError::NonAscii) => {
trace::debug!(
classes = %classes.as_ref().escape_default(),
"Classes::with_classes: Ignoring classes due to non-ASCII chars"
);
return self;
}
_ => Cow::Borrowed(""),
let Some(normalized) =
util::normalize_ascii_or_empty(classes.as_ref(), "Classes::with_classes")
else {
return self;
};
match op {
ClassesOp::Add => {
@ -116,25 +110,24 @@ impl Classes {
self.0.retain(|c| !to_remove.contains(c.as_str()));
}
ClassesOp::Replace(classes_to_replace) => {
let mut pos = self.0.len();
let classes_to_replace = match util::normalize_ascii(classes_to_replace.as_ref()) {
Ok(c) => c,
Err(util::NormalizeAsciiError::NonAscii) => {
trace::debug!(
classes = %classes_to_replace.as_ref().escape_default(),
"Classes::with_classes: Invalid replace classes due to non-ASCII chars"
);
return self;
}
_ => Cow::Borrowed(""),
let Some(classes_to_replace) = util::normalize_ascii_or_empty(
classes_to_replace.as_ref(),
"ClassesOp::Replace",
) else {
return self;
};
let mut pos = self.0.len();
let mut replaced = false;
for class in classes_to_replace.as_ref().split_ascii_whitespace() {
if let Some(replace_pos) = self.0.iter().position(|c| c == class) {
self.0.remove(replace_pos);
pos = pos.min(replace_pos);
replaced = true;
}
}
self.add(normalized.as_ref().split_ascii_whitespace(), pos);
if replaced {
self.add(normalized.as_ref().split_ascii_whitespace(), pos);
}
}
ClassesOp::Toggle => {
for class in normalized.as_ref().split_ascii_whitespace() {

View file

@ -128,6 +128,30 @@ pub fn normalize_ascii<'a>(input: &'a str) -> Result<Cow<'a, str>, NormalizeAsci
Ok(Cow::Owned(output))
}
/// Normaliza una cadena ASCII, opcionalmente vacía, con uno o varios tokens separados.
///
/// - Devuelve `Some(Cow)` si la entrada es válida ASCII (normalizada a minúsculas).
/// - Devuelve `Some(Cow::Borrowed(""))` si la entrada es `""` o queda vacía tras recortar.
/// - Devuelve `None` si la entrada contiene bytes non-ASCII; y emite un `trace::debug!` con el
/// campo `target`.
#[inline]
pub fn normalize_ascii_or_empty<'a>(input: &'a str, target: &'static str) -> Option<Cow<'a, str>> {
match normalize_ascii(input) {
Ok(s) => Some(s),
Err(NormalizeAsciiError::NonAscii) => {
trace::debug!(
target = %target,
input = %input.escape_default(),
"Ignoring due to non-ASCII chars"
);
None
}
Err(NormalizeAsciiError::IsEmpty | NormalizeAsciiError::EmptyAfterTrimming) => {
Some(Cow::Borrowed(""))
}
}
}
/// Resuelve y valida la ruta de un directorio existente, devolviendo una ruta absoluta.
///
/// - Si la ruta es relativa, se resuelve respecto al directorio del proyecto según la variable de