diff --git a/crates/oxc_transformer/src/options/babel/env/targets.rs b/crates/oxc_transformer/src/options/babel/env/targets.rs index 5432d93bdf744..d9998bb5c6f87 100644 --- a/crates/oxc_transformer/src/options/babel/env/targets.rs +++ b/crates/oxc_transformer/src/options/babel/env/targets.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use rustc_hash::FxHashMap; use serde::Deserialize; @@ -5,7 +7,7 @@ use oxc_diagnostics::Error; pub use browserslist::Version; -use crate::options::{BrowserslistQuery, EngineTargets}; +use crate::options::{engine_targets::Engine, BrowserslistQuery, EngineTargets}; /// #[derive(Debug, Deserialize)] @@ -39,7 +41,7 @@ impl TryFrom for EngineTargets { BabelTargets::String(s) => BrowserslistQuery::Single(s).exec(), BabelTargets::Array(v) => BrowserslistQuery::Multiple(v).exec(), BabelTargets::Map(map) => { - let mut targets = Self::default(); + let mut engine_targets = Self::default(); for (key, value) in map { // TODO: Implement these targets. if matches!(key.as_str(), "esmodules" | "browsers") { @@ -63,12 +65,12 @@ impl TryFrom for EngineTargets { // TODO: Some keys are not implemented yet. // : // Supported environments: android, chrome, deno, edge, electron, firefox, ie, ios, node, opera, rhino, safari, samsung. - let Ok(target) = targets.get_version_mut(&key) else { - continue; + let Ok(engine) = Engine::from_str(&key) else { + return Err(Error::msg(format!("engine '{key}' is not supported."))); }; match Version::parse(&v) { Ok(version) => { - target.replace(version); + engine_targets.targets.insert(engine, version); } Err(err) => { return Err(oxc_diagnostics::Error::msg(format!( @@ -77,7 +79,7 @@ impl TryFrom for EngineTargets { } } } - Ok(targets) + Ok(engine_targets) } } } diff --git a/crates/oxc_transformer/src/options/engine_targets.rs b/crates/oxc_transformer/src/options/engine_targets.rs index fe1ac2ac3ebd8..dad81a77aa1cd 100644 --- a/crates/oxc_transformer/src/options/engine_targets.rs +++ b/crates/oxc_transformer/src/options/engine_targets.rs @@ -1,25 +1,63 @@ +use std::str::FromStr; + use browserslist::Version; +use rustc_hash::FxHashMap; use serde::Deserialize; use oxc_diagnostics::Error; use super::{babel::BabelTargets, BrowserslistQuery}; +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum Engine { + Chrome, + Deno, + Edge, + Firefox, + Hermes, + Ie, + Ios, + Node, + Opera, + Rhino, + Safari, + Samsung, + // TODO: electron to chromium + Electron, + // TODO: how to handle? There is a `op_mob` key below. + OperaMobile, +} + +impl FromStr for Engine { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "chrome" | "and_chr" => Ok(Self::Chrome), + "deno" => Ok(Self::Deno), + "edge" => Ok(Self::Edge), + "firefox" | "and_ff" => Ok(Self::Firefox), + "hermes" => Ok(Self::Hermes), + "ie" | "ie_mob" => Ok(Self::Ie), + "ios" | "ios_saf" => Ok(Self::Ios), + "node" => Ok(Self::Node), + "opera" | "op_mob" => Ok(Self::Opera), + "rhino" => Ok(Self::Rhino), + "safari" => Ok(Self::Safari), + "samsung" => Ok(Self::Samsung), + "electron" => Ok(Self::Electron), + "opera_mobile" => Ok(Self::OperaMobile), + _ => Err(()), + } + } +} + /// A map of engine names to minimum supported versions. -#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize)] +#[derive(Debug, Default, Clone, Deserialize)] #[serde(try_from = "BabelTargets")] pub struct EngineTargets { - chrome: Option, - deno: Option, - edge: Option, - firefox: Option, - hermes: Option, - ie: Option, - ios: Option, - node: Option, - opera: Option, - rhino: Option, - safari: Option, + pub(crate) targets: FxHashMap, } impl EngineTargets { @@ -32,77 +70,40 @@ impl EngineTargets { /// Returns true if all fields are [None]. pub fn is_any_target(&self) -> bool { - *self == Self::default() + self.targets.is_empty() } - pub fn should_enable(&self, targets: &EngineTargets) -> bool { - if let (Some(v1), Some(v2)) = (&self.chrome, &targets.chrome) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.deno, &targets.deno) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.edge, &targets.edge) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.firefox, &targets.firefox) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.hermes, &targets.hermes) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.ie, &targets.ie) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.ios, &targets.ios) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.node, &targets.node) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.opera, &targets.opera) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.rhino, &targets.rhino) { - return v1 < v2; - } - if let (Some(v1), Some(v2)) = (&self.safari, &targets.safari) { - return v1 < v2; + pub fn should_enable(&self, engine_targets: &EngineTargets) -> bool { + for (engine, version) in &engine_targets.targets { + if let Some(v) = self.targets.get(engine) { + if v < version { + return true; + } + } } false } /// Parses the value returned from `browserslist`. pub fn parse_versions(versions: Vec<(String, String)>) -> Self { - let mut targets = Self::default(); - for (name, version) in versions { - let Ok(browser) = targets.get_version_mut(&name) else { + let mut engine_targets = Self::default(); + for (engine, version) in versions { + let Ok(engine) = Engine::from_str(&engine) else { continue; }; - let Ok(version) = version.parse::() else { + let Ok(version) = Version::from_str(&version) else { continue; }; - if browser.is_none() || browser.is_some_and(|v| version < v) { - browser.replace(version); - } - } - targets - } - - pub(crate) fn get_version_mut(&mut self, key: &str) -> Result<&mut Option, ()> { - match key { - "chrome" | "and_chr" => Ok(&mut self.chrome), - "deno" => Ok(&mut self.deno), - "edge" => Ok(&mut self.edge), - "firefox" | "and_ff" => Ok(&mut self.firefox), - "hermes" => Ok(&mut self.hermes), - "ie" | "ie_mob" => Ok(&mut self.ie), - "ios" | "ios_saf" => Ok(&mut self.ios), - "node" => Ok(&mut self.node), - "opera" | "op_mob" => Ok(&mut self.opera), - "rhino" => Ok(&mut self.rhino), - "safari" => Ok(&mut self.safari), - _ => Err(()), + engine_targets + .targets + .entry(engine) + .and_modify(|v| { + if version < *v { + *v = version; + } + }) + .or_insert(version); } + engine_targets } }