Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down
14 changes: 7 additions & 7 deletions crates/oxc_transformer/src/options/babel/env/data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use std::sync::OnceLock;

use rustc_hash::FxHashMap;

use super::Targets;
use super::EngineTargets;

/// Reference: <https://github.com/swc-project/swc/blob/ea14fc8e5996dcd736b8deb4cc99262d07dfff44/crates/swc_ecma_preset_env/src/transform_data.rs#L194-L218>
pub fn features() -> &'static FxHashMap<String, Targets> {
static FEATURES: OnceLock<FxHashMap<String, Targets>> = OnceLock::new();
pub fn features() -> &'static FxHashMap<String, EngineTargets> {
static FEATURES: OnceLock<FxHashMap<String, EngineTargets>> = OnceLock::new();
FEATURES.get_or_init(|| {
let mut map: FxHashMap<String, FxHashMap<String, String>> =
serde_json::from_str(include_str!("./@babel/compat_data/data/plugins.json")).unwrap();
Expand All @@ -25,17 +25,17 @@ pub fn features() -> &'static FxHashMap<String, Targets> {
versions.remove("safari");
}
let versions = versions.into_iter().collect::<Vec<_>>();
(feature, Targets::parse_versions(versions))
(feature, EngineTargets::parse_versions(versions))
})
.collect()
})
}

/// Reference: <https://github.com/swc-project/swc/blob/ea14fc8e5996dcd736b8deb4cc99262d07dfff44/crates/swc_ecma_preset_env/src/transform_data.rs#L220-L237>
pub fn bugfix_features() -> &'static FxHashMap<String, Targets> {
static BUGFIX_FEATURES: OnceLock<FxHashMap<String, Targets>> = OnceLock::new();
pub fn bugfix_features() -> &'static FxHashMap<String, EngineTargets> {
static BUGFIX_FEATURES: OnceLock<FxHashMap<String, EngineTargets>> = OnceLock::new();
BUGFIX_FEATURES.get_or_init(|| {
let map = serde_json::from_str::<FxHashMap<String, Targets>>(include_str!(
let map = serde_json::from_str::<FxHashMap<String, EngineTargets>>(include_str!(
"./@babel/compat_data/data/plugin_bugfixes.json"
))
.unwrap();
Expand Down
13 changes: 9 additions & 4 deletions crates/oxc_transformer/src/options/babel/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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,
Expand Down
10 changes: 5 additions & 5 deletions crates/oxc_transformer/src/options/babel/env/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -14,13 +14,13 @@ pub enum Query {
Multiple(Vec<String>),
}

fn cache() -> &'static DashMap<Query, Targets> {
static CACHE: OnceLock<DashMap<Query, Targets>> = OnceLock::new();
fn cache() -> &'static DashMap<Query, EngineTargets> {
static CACHE: OnceLock<DashMap<Query, EngineTargets>> = OnceLock::new();
CACHE.get_or_init(DashMap::new)
}

impl Query {
pub fn exec(&self) -> Result<Targets, Error> {
pub fn exec(&self) -> Result<EngineTargets, Error> {
if let Some(v) = cache().get(self) {
return Ok(v.clone());
}
Expand Down Expand Up @@ -48,7 +48,7 @@ impl Query {
.into_iter()
.map(|d| (d.name().to_string(), d.version().to_string()))
.collect::<Vec<_>>();
Targets::parse_versions(versions)
EngineTargets::parse_versions(versions)
}
Err(err) => {
return Err(OxcDiagnostic::error(format!("failed to resolve query: {err}")).into())
Expand Down
111 changes: 4 additions & 107 deletions crates/oxc_transformer/src/options/babel/env/targets.rs
Original file line number Diff line number Diff line change
@@ -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<Version>,
deno: Option<Version>,
edge: Option<Version>,
firefox: Option<Version>,
hermes: Option<Version>,
ie: Option<Version>,
ios: Option<Version>,
node: Option<Version>,
opera: Option<Version>,
rhino: Option<Version>,
safari: Option<Version>,
}

impl Targets {
/// # Errors
///
/// * Query is invalid.
pub fn try_from_query(query: &str) -> Result<Self, Error> {
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::<Version>() 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<Version>, ()> {
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;

/// <https://babel.dev/docs/babel-preset-env#targets>
#[derive(Debug, Deserialize)]
Expand All @@ -136,7 +33,7 @@ pub enum BabelTargetsValue {
Float(f64),
}

impl TryFrom<BabelTargets> for Targets {
impl TryFrom<BabelTargets> for EngineTargets {
type Error = Error;
fn try_from(value: BabelTargets) -> Result<Self, Self::Error> {
match value {
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_transformer/src/options/babel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
108 changes: 108 additions & 0 deletions crates/oxc_transformer/src/options/engine_targets.rs
Original file line number Diff line number Diff line change
@@ -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<Version>,
deno: Option<Version>,
edge: Option<Version>,
firefox: Option<Version>,
hermes: Option<Version>,
ie: Option<Version>,
ios: Option<Version>,
node: Option<Version>,
opera: Option<Version>,
rhino: Option<Version>,
safari: Option<Version>,
}

impl EngineTargets {
/// # Errors
///
/// * Query is invalid.
pub fn try_from_query(query: &str) -> Result<Self, Error> {
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::<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<Version>, ()> {
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(()),
}
}
}
4 changes: 2 additions & 2 deletions crates/oxc_transformer/src/options/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
es2021::ES2021Options,
es2022::{ClassPropertiesOptions, ES2022Options},
regexp::RegExpOptions,
Targets,
EngineTargets,
};

use super::babel::BabelEnvOptions;
Expand Down Expand Up @@ -139,7 +139,7 @@ impl EnvOptions {
/// * When the query failed to parse.
pub fn from_browserslist_query(query: &str) -> Result<Self, Error> {
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.
// <https://babel.dev/docs/babel-preset-env#bugfixes>
bugfixes: true,
Expand Down
8 changes: 6 additions & 2 deletions crates/oxc_transformer/src/options/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod babel;
mod engine_targets;
mod env;

use std::path::PathBuf;
Expand All @@ -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;

/// <https://babel.dev/docs/options>
#[derive(Debug, Default, Clone)]
Expand Down