Skip to content

Commit

Permalink
refactor(transformer): add Engine enum for EngineTargets (#7161)
Browse files Browse the repository at this point in the history
  • Loading branch information
Boshen committed Nov 6, 2024
1 parent fd9b44c commit a981caf
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 77 deletions.
14 changes: 8 additions & 6 deletions crates/oxc_transformer/src/options/babel/env/targets.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::str::FromStr;

use rustc_hash::FxHashMap;
use serde::Deserialize;

use oxc_diagnostics::Error;

pub use browserslist::Version;

use crate::options::{BrowserslistQuery, EngineTargets};
use crate::options::{engine_targets::Engine, BrowserslistQuery, EngineTargets};

/// <https://babel.dev/docs/babel-preset-env#targets>
#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -39,7 +41,7 @@ impl TryFrom<BabelTargets> 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") {
Expand All @@ -63,12 +65,12 @@ impl TryFrom<BabelTargets> for EngineTargets {
// TODO: Some keys are not implemented yet.
// <https://babel.dev/docs/options#targets>:
// 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!(
Expand All @@ -77,7 +79,7 @@ impl TryFrom<BabelTargets> for EngineTargets {
}
}
}
Ok(targets)
Ok(engine_targets)
}
}
}
Expand Down
143 changes: 72 additions & 71 deletions crates/oxc_transformer/src/options/engine_targets.rs
Original file line number Diff line number Diff line change
@@ -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<Self, Self::Err> {
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<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>,
pub(crate) targets: FxHashMap<Engine, Version>,
}

impl EngineTargets {
Expand All @@ -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::<Version>() 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<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(()),
engine_targets
.targets
.entry(engine)
.and_modify(|v| {
if version < *v {
*v = version;
}
})
.or_insert(version);
}
engine_targets
}
}

0 comments on commit a981caf

Please sign in to comment.