use std::sync::LazyLock;
use browserslist::Opts;
use regex::Regex;
#[derive(Debug, Default)]
pub struct BrowserslistHandlerConfig<'a> {
pub config_path: Option<String>,
pub env: Option<String>,
pub env_or_query: Option<String>,
pub query: Option<String>,
pub context: &'a str,
}
pub fn parse<'a>(input: Option<&str>, context: &'a str) -> BrowserslistHandlerConfig<'a> {
let Some(input) = input else {
return BrowserslistHandlerConfig {
context,
..Default::default()
};
};
static BROWSERSLIST_INPUT_RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"^(?:((?:[A-Z]:)?[/\\].*?))?(?::(.+?))?$")
.expect("Should initialize browserslist input regex")
});
if let Some(caps) = BROWSERSLIST_INPUT_RE.captures(input) {
let config_path = caps.get(1).map(|m| m.as_str().to_string());
let env = caps.get(2).map(|m| m.as_str().to_string());
if config_path.is_some() {
return BrowserslistHandlerConfig {
config_path,
env,
env_or_query: None,
query: None,
context,
};
}
}
BrowserslistHandlerConfig {
config_path: None,
env: None,
env_or_query: Some(input.to_string()),
query: None,
context,
}
}
pub fn load_browserslist(input: Option<&str>, context: &str) -> Option<Vec<String>> {
let BrowserslistHandlerConfig {
config_path,
env,
env_or_query,
query,
context,
} = parse(input, context);
let mut opts = Opts::default();
if let Some(config) = config_path {
opts.config = Some(config);
} else {
opts.path = Some(context.to_string());
}
if let Some(e) = env {
opts.env = Some(e);
}
match if let Some(q) = query {
browserslist::resolve(vec![q], &opts)
} else if let Some(env_or_query_str) = env_or_query {
match browserslist::resolve(vec![env_or_query_str.as_str()], &opts) {
Ok(browsers) => {
Ok(browsers)
}
Err(_) => {
opts.env = Some(env_or_query_str);
#[cfg(target_arch = "wasm32")]
{
Ok(Vec::new())
}
#[cfg(not(target_arch = "wasm32"))]
{
browserslist::execute(&opts)
}
}
}
} else {
#[cfg(target_arch = "wasm32")]
{
Ok(Vec::new())
}
#[cfg(not(target_arch = "wasm32"))]
{
browserslist::execute(&opts)
}
} {
Ok(browsers) => Some(browsers.into_iter().map(|d| d.to_string()).collect()),
Err(_) => None,
}
}