use std::{collections::BTreeSet, sync::Arc};
#[allow(missing_debug_implementations)]
#[allow(clippy::type_complexity)]
#[derive(Clone)]
pub struct Scanner {
scan_fn: Arc<dyn Fn(&str) -> BTreeSet<&str> + Send + Sync>,
}
impl Scanner {
pub fn from_fn<T: 'static + Fn(&str) -> BTreeSet<&str> + Send + Sync>(scan_fn: T) -> Self {
Self {
scan_fn: Arc::new(scan_fn),
}
}
pub(crate) fn scan<'a>(&self, val: &'a str) -> BTreeSet<&'a str> {
(self.scan_fn)(val)
}
}
impl Default for Scanner {
fn default() -> Self {
Self {
scan_fn: Arc::new(|val| {
val.split([' ', '\n', '\'', '"', '`', '\\'])
.collect::<BTreeSet<&str>>()
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
#[test]
fn default_scanner_test() {
assert_eq!(
Scanner::default().scan("test bg-red-500 'hello' content-[some_[_square]_brackets] foo-bar sm:focus:ring hover:bg-black border-[#333] text-[color:var(--hello)]"),
BTreeSet::from([
"",
"test",
"bg-red-500",
"hello",
"content-[some_[_square]_brackets]",
"foo-bar",
"sm:focus:ring",
"hover:bg-black",
"border-[#333]",
"text-[color:var(--hello)]",
])
);
}
#[test]
fn custom_scanner_test() {
let scanner = Scanner::from_fn(|val| val.split(|ch| ch == '|').collect::<BTreeSet<&str>>());
assert_eq!(
scanner.scan("test|bg-red-500|'hello'"),
BTreeSet::from(["test", "bg-red-500", "'hello'"])
);
}
#[test]
fn utf8_scan() {
assert_eq!(
Scanner::default().scan("<div class=\"before:content-[J\u{e4}s\u{f8}n_Doe] content-[\u{2192}]\">\u{306}</div>"),
BTreeSet::from([
"<div",
">\u{306}</div>",
"before:content-[J\u{e4}s\u{f8}n_Doe]",
"class=",
"content-[\u{2192}]",
])
);
}
#[test]
fn scan_prevent_splitting_arbitrary_values() {
assert_eq!(
Scanner::default().scan(r#"<div class="bg-red-300 content-['hello:>"']"></div>"#),
BTreeSet::from([
"<div",
"></div>",
"bg-red-300",
"class=",
"content-['hello:>"']",
])
);
}
#[test]
fn scan_with_arbitrary_variant() {
assert_eq!(
Scanner::default().scan(r#"<div class="[input[type='text']]:block"></div>"#),
BTreeSet::from(["<div", "></div>", "class=", "[input[type='text']]:block",])
);
}
}