From 481f7e603e16c9cafabcfc9db292a205a4ede319 Mon Sep 17 00:00:00 2001 From: Boshen <1430279+Boshen@users.noreply.github.com> Date: Tue, 5 Nov 2024 13:32:11 +0000 Subject: [PATCH] refactor(transformer): change `Targets` to `EngineTargets` (#7142) --- crates/oxc_transformer/src/lib.rs | 4 +- .../src/options/babel/env/data/mod.rs | 14 +-- .../src/options/babel/env/mod.rs | 13 +- .../src/options/babel/env/query.rs | 10 +- .../src/options/babel/env/targets.rs | 111 +----------------- .../oxc_transformer/src/options/babel/mod.rs | 2 +- .../src/options/engine_targets.rs | 108 +++++++++++++++++ crates/oxc_transformer/src/options/env.rs | 4 +- crates/oxc_transformer/src/options/mod.rs | 8 +- 9 files changed, 144 insertions(+), 130 deletions(-) create mode 100644 crates/oxc_transformer/src/options/engine_targets.rs diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index fb288016a027e..8e583531cebe1 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -55,8 +55,8 @@ pub use crate::{ es2015::{ArrowFunctionsOptions, ES2015Options}, jsx::{JsxOptions, JsxRuntime, ReactRefreshOptions}, options::{ - babel::{BabelEnvOptions, BabelOptions, Targets}, - ESTarget, EnvOptions, TransformOptions, + babel::{BabelEnvOptions, BabelOptions}, + ESTarget, EngineTargets, EnvOptions, TransformOptions, }, plugins::*, typescript::{RewriteExtensionsMode, TypeScriptOptions}, diff --git a/crates/oxc_transformer/src/options/babel/env/data/mod.rs b/crates/oxc_transformer/src/options/babel/env/data/mod.rs index 81f3bb19f6e80..42c6f4157ac2a 100644 --- a/crates/oxc_transformer/src/options/babel/env/data/mod.rs +++ b/crates/oxc_transformer/src/options/babel/env/data/mod.rs @@ -2,11 +2,11 @@ use std::sync::OnceLock; use rustc_hash::FxHashMap; -use super::Targets; +use super::EngineTargets; /// Reference: -pub fn features() -> &'static FxHashMap { - static FEATURES: OnceLock> = OnceLock::new(); +pub fn features() -> &'static FxHashMap { + static FEATURES: OnceLock> = OnceLock::new(); FEATURES.get_or_init(|| { let mut map: FxHashMap> = serde_json::from_str(include_str!("./@babel/compat_data/data/plugins.json")).unwrap(); @@ -25,17 +25,17 @@ pub fn features() -> &'static FxHashMap { versions.remove("safari"); } let versions = versions.into_iter().collect::>(); - (feature, Targets::parse_versions(versions)) + (feature, EngineTargets::parse_versions(versions)) }) .collect() }) } /// Reference: -pub fn bugfix_features() -> &'static FxHashMap { - static BUGFIX_FEATURES: OnceLock> = OnceLock::new(); +pub fn bugfix_features() -> &'static FxHashMap { + static BUGFIX_FEATURES: OnceLock> = OnceLock::new(); BUGFIX_FEATURES.get_or_init(|| { - let map = serde_json::from_str::>(include_str!( + let map = serde_json::from_str::>(include_str!( "./@babel/compat_data/data/plugin_bugfixes.json" )) .unwrap(); diff --git a/crates/oxc_transformer/src/options/babel/env/mod.rs b/crates/oxc_transformer/src/options/babel/env/mod.rs index 3d9132f33ebc7..1a7a6290cef2e 100644 --- a/crates/oxc_transformer/src/options/babel/env/mod.rs +++ b/crates/oxc_transformer/src/options/babel/env/mod.rs @@ -2,11 +2,16 @@ mod data; mod query; mod targets; -pub use data::{bugfix_features, features}; -pub use targets::Targets; - use serde::Deserialize; +pub use self::{ + data::{bugfix_features, features}, + query::Query, + targets::BabelTargets, +}; + +use crate::options::EngineTargets; + fn default_as_true() -> bool { true } @@ -15,7 +20,7 @@ fn default_as_true() -> bool { #[serde(default, rename_all = "camelCase", deny_unknown_fields)] pub struct BabelEnvOptions { #[serde(default)] - pub targets: Targets, + pub targets: EngineTargets, #[serde(default = "default_as_true")] pub bugfixes: bool, diff --git a/crates/oxc_transformer/src/options/babel/env/query.rs b/crates/oxc_transformer/src/options/babel/env/query.rs index c02c1721f0951..811b646d9383b 100644 --- a/crates/oxc_transformer/src/options/babel/env/query.rs +++ b/crates/oxc_transformer/src/options/babel/env/query.rs @@ -5,7 +5,7 @@ use serde::Deserialize; use oxc_diagnostics::{Error, OxcDiagnostic}; -use super::Targets; +use super::EngineTargets; #[derive(Debug, Clone, Deserialize, Eq, PartialEq, PartialOrd, Ord, Hash)] #[serde(untagged)] @@ -14,13 +14,13 @@ pub enum Query { Multiple(Vec), } -fn cache() -> &'static DashMap { - static CACHE: OnceLock> = OnceLock::new(); +fn cache() -> &'static DashMap { + static CACHE: OnceLock> = OnceLock::new(); CACHE.get_or_init(DashMap::new) } impl Query { - pub fn exec(&self) -> Result { + pub fn exec(&self) -> Result { if let Some(v) = cache().get(self) { return Ok(v.clone()); } @@ -48,7 +48,7 @@ impl Query { .into_iter() .map(|d| (d.name().to_string(), d.version().to_string())) .collect::>(); - Targets::parse_versions(versions) + EngineTargets::parse_versions(versions) } Err(err) => { return Err(OxcDiagnostic::error(format!("failed to resolve query: {err}")).into()) diff --git a/crates/oxc_transformer/src/options/babel/env/targets.rs b/crates/oxc_transformer/src/options/babel/env/targets.rs index b7cc0a51d99f6..e47e1742e22ed 100644 --- a/crates/oxc_transformer/src/options/babel/env/targets.rs +++ b/crates/oxc_transformer/src/options/babel/env/targets.rs @@ -1,115 +1,12 @@ -use oxc_diagnostics::Error; use rustc_hash::FxHashMap; use serde::Deserialize; +use oxc_diagnostics::Error; + pub use browserslist::Version; use super::query::Query; - -/// A map of browser names to data for feature support in browser. -/// -/// This type mainly stores `minimum version for each browsers with support for -/// a feature`. -#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize)] -#[serde(try_from = "BabelTargets")] -pub struct Targets { - chrome: Option, - deno: Option, - edge: Option, - firefox: Option, - hermes: Option, - ie: Option, - ios: Option, - node: Option, - opera: Option, - rhino: Option, - safari: Option, -} - -impl Targets { - /// # Errors - /// - /// * Query is invalid. - pub fn try_from_query(query: &str) -> Result { - Query::Single(query.to_string()).exec() - } - - /// Returns true if all fields are [None]. - pub fn is_any_target(&self) -> bool { - *self == Self::default() - } - - pub fn should_enable(&self, targets: &Targets) -> 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; - } - 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 { - continue; - }; - let Ok(version) = version.parse::() else { - continue; - }; - if browser.is_none() || browser.is_some_and(|v| version < v) { - browser.replace(version); - } - } - targets - } - - 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(()), - } - } -} +use crate::options::EngineTargets; /// #[derive(Debug, Deserialize)] @@ -136,7 +33,7 @@ pub enum BabelTargetsValue { Float(f64), } -impl TryFrom for Targets { +impl TryFrom for EngineTargets { type Error = Error; fn try_from(value: BabelTargets) -> Result { match value { diff --git a/crates/oxc_transformer/src/options/babel/mod.rs b/crates/oxc_transformer/src/options/babel/mod.rs index 252d14b5a83a7..d100aa98fa280 100644 --- a/crates/oxc_transformer/src/options/babel/mod.rs +++ b/crates/oxc_transformer/src/options/babel/mod.rs @@ -8,7 +8,7 @@ use serde::{de::DeserializeOwned, Deserialize}; use crate::CompilerAssumptions; -pub use self::env::{BabelEnvOptions, Targets}; +pub use self::env::{BabelEnvOptions, BabelTargets, Query}; use self::{plugins::BabelPlugins, presets::BabelPresets}; /// Babel options diff --git a/crates/oxc_transformer/src/options/engine_targets.rs b/crates/oxc_transformer/src/options/engine_targets.rs new file mode 100644 index 0000000000000..1a76586e0f379 --- /dev/null +++ b/crates/oxc_transformer/src/options/engine_targets.rs @@ -0,0 +1,108 @@ +use browserslist::Version; +use serde::Deserialize; + +use oxc_diagnostics::Error; + +use super::babel::{BabelTargets, Query}; + +/// A map of engine names to minimum supported versions. +#[derive(Debug, Default, Clone, Eq, PartialEq, 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, +} + +impl EngineTargets { + /// # Errors + /// + /// * Query is invalid. + pub fn try_from_query(query: &str) -> Result { + Query::Single(query.to_string()).exec() + } + + /// Returns true if all fields are [None]. + pub fn is_any_target(&self) -> bool { + *self == Self::default() + } + + 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; + } + 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 { + continue; + }; + let Ok(version) = version.parse::() 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(()), + } + } +} diff --git a/crates/oxc_transformer/src/options/env.rs b/crates/oxc_transformer/src/options/env.rs index c459ad1426172..e652b32af106c 100644 --- a/crates/oxc_transformer/src/options/env.rs +++ b/crates/oxc_transformer/src/options/env.rs @@ -14,7 +14,7 @@ use crate::{ es2021::ES2021Options, es2022::{ClassPropertiesOptions, ES2022Options}, regexp::RegExpOptions, - Targets, + EngineTargets, }; use super::babel::BabelEnvOptions; @@ -139,7 +139,7 @@ impl EnvOptions { /// * When the query failed to parse. pub fn from_browserslist_query(query: &str) -> Result { Self::try_from(BabelEnvOptions { - targets: Targets::try_from_query(query)?, + targets: EngineTargets::try_from_query(query)?, // This option will be enabled by default in Babel 8. // bugfixes: true, diff --git a/crates/oxc_transformer/src/options/mod.rs b/crates/oxc_transformer/src/options/mod.rs index 9b21e04274fc7..bf49cab3ead39 100644 --- a/crates/oxc_transformer/src/options/mod.rs +++ b/crates/oxc_transformer/src/options/mod.rs @@ -1,4 +1,5 @@ pub mod babel; +mod engine_targets; mod env; use std::path::PathBuf; @@ -22,9 +23,12 @@ use crate::{ ReactRefreshOptions, }; -pub use env::{ESTarget, EnvOptions}; +pub use self::{ + engine_targets::EngineTargets, + env::{ESTarget, EnvOptions}, +}; -use babel::BabelOptions; +use self::babel::BabelOptions; /// #[derive(Debug, Default, Clone)]