pub use error::Error;
pub use opts::Opts;
use parser::parse_browserslist_query;
pub use queries::Distrib;
pub use semver::Version;
#[cfg(all(feature = "wasm_bindgen", target_arch = "wasm32"))]
pub use wasm::browserslist;
mod data;
mod date;
mod error;
mod generated;
mod opts;
mod parser;
mod queries;
mod semver;
#[cfg(all(feature = "wasm_bindgen", target_arch = "wasm32"))]
mod wasm;
pub fn resolve<S>(queries: &[S], opts: &Opts) -> Result<Vec<Distrib>, Error>
where
S: AsRef<str>,
{
match queries.len() {
1 => _resolve(queries[0].as_ref(), opts),
_ => {
let total_len: usize = queries.iter().map(|q| q.as_ref().len() + 1).sum();
let mut s = String::with_capacity(total_len);
for (i, q) in queries.iter().enumerate() {
if i > 0 {
s.push(',');
}
s.push_str(q.as_ref());
}
_resolve(&s, opts)
}
}
}
fn _resolve(query: &str, opts: &Opts) -> Result<Vec<Distrib>, Error> {
let queries = parse_browserslist_query(query)?;
let mut distribs = vec![];
for (i, current) in queries.1.into_iter().enumerate() {
if i == 0 && current.negated {
return handle_first_negated_error(current.raw.to_string());
}
let dist = queries::query(current.atom, opts)?;
apply_query_operation(&mut distribs, dist, current.negated, current.is_and);
}
sort_and_dedup_distribs(&mut distribs);
Ok(distribs)
}
fn apply_query_operation(
distribs: &mut Vec<Distrib>,
dist: Vec<Distrib>,
negated: bool,
is_and: bool,
) {
if negated {
distribs.retain(|d| !dist.contains(d));
} else if is_and {
distribs.retain(|d| dist.contains(d));
} else {
distribs.extend(dist);
}
}
fn sort_and_dedup_distribs(distribs: &mut Vec<Distrib>) {
if distribs.is_empty() {
return;
}
distribs.sort_by_cached_key(|d| {
let version = d.version().parse::<semver::Version>().unwrap_or_default();
(d.name().to_string(), std::cmp::Reverse(version))
});
distribs.dedup();
}
#[cold]
fn handle_first_negated_error(raw: String) -> Result<Vec<Distrib>, Error> {
Err(Error::NotAtFirst(raw))
}