mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(transformer): change Targets to EngineTargets (#7142)
This commit is contained in:
parent
55e6989830
commit
481f7e603e
9 changed files with 144 additions and 130 deletions
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<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());
|
||||
}
|
||||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
108
crates/oxc_transformer/src/options/engine_targets.rs
Normal file
108
crates/oxc_transformer/src/options/engine_targets.rs
Normal file
|
|
@ -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(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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, 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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/// <https://babel.dev/docs/options>
|
||||
#[derive(Debug, Default, Clone)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue