From ad3a2f518e6a8f16bc2e2f36e5cfae7acfbea0a3 Mon Sep 17 00:00:00 2001 From: Boshen <1430279+Boshen@users.noreply.github.com> Date: Thu, 7 Nov 2024 07:39:33 +0000 Subject: [PATCH] feat(tasks/compat_data): generate our own compat table (#7176) --- .ignore | 2 + Cargo.lock | 10 + crates/oxc_transformer/src/lib.rs | 2 +- .../data/@babel/compat_data/data/plugins.json | 764 -------------- .../babel/env/data/esbuild/features.json | 23 - .../src/options/babel/env/data/mod.rs | 32 - .../src/options/babel/env/mod.rs | 12 +- .../src/options/babel/env/targets.rs | 2 +- .../src/options/engine_targets.rs | 35 +- crates/oxc_transformer/src/options/env.rs | 53 +- .../src/options/es_features.rs | 777 ++++++++++++++ crates/oxc_transformer/src/options/mod.rs | 4 +- pnpm-lock.yaml | 6 +- tasks/compat_data/Cargo.toml | 11 + tasks/compat_data/build.js | 81 +- tasks/compat_data/data.json | 970 ++++++++++++++++++ tasks/compat_data/es-features.js | 322 ++++++ tasks/compat_data/plugin-features.js | 224 ---- tasks/compat_data/src/lib.rs | 79 ++ tasks/compat_data/src/main.rs | 6 +- .../snapshots/oxc.snap.md | 8 +- 21 files changed, 2264 insertions(+), 1159 deletions(-) delete mode 100644 crates/oxc_transformer/src/options/babel/env/data/@babel/compat_data/data/plugins.json delete mode 100644 crates/oxc_transformer/src/options/babel/env/data/esbuild/features.json delete mode 100644 crates/oxc_transformer/src/options/babel/env/data/mod.rs create mode 100644 crates/oxc_transformer/src/options/es_features.rs create mode 100644 tasks/compat_data/data.json create mode 100644 tasks/compat_data/es-features.js delete mode 100644 tasks/compat_data/plugin-features.js diff --git a/.ignore b/.ignore index d124948fa951c..0be9b377cc423 100644 --- a/.ignore +++ b/.ignore @@ -9,3 +9,5 @@ tasks/coverage/typescript/** tasks/prettier_conformance/prettier/** **/*.snap + +crates/oxc_transformer/src/options/es_features.rs diff --git a/Cargo.lock b/Cargo.lock index d495e28ec1337..f1bd0cc0d8abc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1570,6 +1570,16 @@ dependencies = [ [[package]] name = "oxc_compat_data" version = "0.0.0" +dependencies = [ + "oxc_tasks_common", + "oxc_transformer", + "prettyplease", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", +] [[package]] name = "oxc_coverage" diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 06567847501fb..bedcf7d7a7c16 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -56,7 +56,7 @@ pub use crate::{ jsx::{JsxOptions, JsxRuntime, ReactRefreshOptions}, options::{ babel::{BabelEnvOptions, BabelOptions}, - ESTarget, EngineTargets, EnvOptions, TransformOptions, + ESTarget, Engine, EngineTargets, EnvOptions, TransformOptions, }, plugins::*, typescript::{RewriteExtensionsMode, TypeScriptOptions}, diff --git a/crates/oxc_transformer/src/options/babel/env/data/@babel/compat_data/data/plugins.json b/crates/oxc_transformer/src/options/babel/env/data/@babel/compat_data/data/plugins.json deleted file mode 100644 index 266426827131f..0000000000000 --- a/crates/oxc_transformer/src/options/babel/env/data/@babel/compat_data/data/plugins.json +++ /dev/null @@ -1,764 +0,0 @@ -{ - "transform-unicode-sets-regex": { - "chrome": "112", - "opera": "98", - "edge": "112", - "firefox": "116", - "safari": "tp", - "node": "20", - "deno": "1.32", - "opera_mobile": "75", - "electron": "24.0" - }, - "transform-class-static-block": { - "chrome": "94", - "opera": "80", - "edge": "94", - "firefox": "93", - "safari": "16.4", - "node": "16.11", - "deno": "1.14", - "ios": "16.4", - "samsung": "17", - "opera_mobile": "66", - "electron": "15.0" - }, - "proposal-class-static-block": { - "chrome": "94", - "opera": "80", - "edge": "94", - "firefox": "93", - "safari": "16.4", - "node": "16.11", - "deno": "1.14", - "ios": "16.4", - "samsung": "17", - "opera_mobile": "66", - "electron": "15.0" - }, - "transform-private-property-in-object": { - "chrome": "91", - "opera": "77", - "edge": "91", - "firefox": "90", - "safari": "15", - "node": "16.9", - "deno": "1.9", - "ios": "15", - "samsung": "16", - "opera_mobile": "64", - "electron": "13.0" - }, - "proposal-private-property-in-object": { - "chrome": "91", - "opera": "77", - "edge": "91", - "firefox": "90", - "safari": "15", - "node": "16.9", - "deno": "1.9", - "ios": "15", - "samsung": "16", - "opera_mobile": "64", - "electron": "13.0" - }, - "transform-class-properties": { - "chrome": "74", - "opera": "62", - "edge": "79", - "firefox": "90", - "safari": "14.1", - "node": "12", - "deno": "1", - "ios": "14.5", - "samsung": "11", - "opera_mobile": "53", - "electron": "6.0" - }, - "proposal-class-properties": { - "chrome": "74", - "opera": "62", - "edge": "79", - "firefox": "90", - "safari": "14.1", - "node": "12", - "deno": "1", - "ios": "14.5", - "samsung": "11", - "opera_mobile": "53", - "electron": "6.0" - }, - "transform-private-methods": { - "chrome": "84", - "opera": "70", - "edge": "84", - "firefox": "90", - "safari": "15", - "node": "14.6", - "deno": "1", - "ios": "15", - "samsung": "14", - "opera_mobile": "60", - "electron": "10.0" - }, - "proposal-private-methods": { - "chrome": "84", - "opera": "70", - "edge": "84", - "firefox": "90", - "safari": "15", - "node": "14.6", - "deno": "1", - "ios": "15", - "samsung": "14", - "opera_mobile": "60", - "electron": "10.0" - }, - "transform-numeric-separator": { - "chrome": "75", - "opera": "62", - "edge": "79", - "firefox": "70", - "safari": "13", - "node": "12.5", - "deno": "1", - "ios": "13", - "samsung": "11", - "rhino": "1.7.14", - "opera_mobile": "54", - "electron": "6.0" - }, - "proposal-numeric-separator": { - "chrome": "75", - "opera": "62", - "edge": "79", - "firefox": "70", - "safari": "13", - "node": "12.5", - "deno": "1", - "ios": "13", - "samsung": "11", - "rhino": "1.7.14", - "opera_mobile": "54", - "electron": "6.0" - }, - "transform-logical-assignment-operators": { - "chrome": "85", - "opera": "71", - "edge": "85", - "firefox": "79", - "safari": "14", - "node": "15", - "deno": "1.2", - "ios": "14", - "samsung": "14", - "opera_mobile": "60", - "electron": "10.0" - }, - "proposal-logical-assignment-operators": { - "chrome": "85", - "opera": "71", - "edge": "85", - "firefox": "79", - "safari": "14", - "node": "15", - "deno": "1.2", - "ios": "14", - "samsung": "14", - "opera_mobile": "60", - "electron": "10.0" - }, - "transform-nullish-coalescing-operator": { - "chrome": "80", - "opera": "67", - "edge": "80", - "firefox": "72", - "safari": "13.1", - "node": "14", - "deno": "1", - "ios": "13.4", - "samsung": "13", - "opera_mobile": "57", - "electron": "8.0" - }, - "proposal-nullish-coalescing-operator": { - "chrome": "80", - "opera": "67", - "edge": "80", - "firefox": "72", - "safari": "13.1", - "node": "14", - "deno": "1", - "ios": "13.4", - "samsung": "13", - "opera_mobile": "57", - "electron": "8.0" - }, - "transform-optional-chaining": { - "chrome": "91", - "opera": "77", - "edge": "91", - "firefox": "74", - "safari": "13.1", - "node": "16.9", - "deno": "1.9", - "ios": "13.4", - "samsung": "16", - "opera_mobile": "64", - "electron": "13.0" - }, - "proposal-optional-chaining": { - "chrome": "91", - "opera": "77", - "edge": "91", - "firefox": "74", - "safari": "13.1", - "node": "16.9", - "deno": "1.9", - "ios": "13.4", - "samsung": "16", - "opera_mobile": "64", - "electron": "13.0" - }, - "transform-json-strings": { - "chrome": "66", - "opera": "53", - "edge": "79", - "firefox": "62", - "safari": "12", - "node": "10", - "deno": "1", - "ios": "12", - "samsung": "9", - "rhino": "1.7.14", - "opera_mobile": "47", - "electron": "3.0" - }, - "proposal-json-strings": { - "chrome": "66", - "opera": "53", - "edge": "79", - "firefox": "62", - "safari": "12", - "node": "10", - "deno": "1", - "ios": "12", - "samsung": "9", - "rhino": "1.7.14", - "opera_mobile": "47", - "electron": "3.0" - }, - "transform-optional-catch-binding": { - "chrome": "66", - "opera": "53", - "edge": "79", - "firefox": "58", - "safari": "11.1", - "node": "10", - "deno": "1", - "ios": "11.3", - "samsung": "9", - "opera_mobile": "47", - "electron": "3.0" - }, - "proposal-optional-catch-binding": { - "chrome": "66", - "opera": "53", - "edge": "79", - "firefox": "58", - "safari": "11.1", - "node": "10", - "deno": "1", - "ios": "11.3", - "samsung": "9", - "opera_mobile": "47", - "electron": "3.0" - }, - "transform-parameters": { - "chrome": "49", - "opera": "36", - "edge": "18", - "firefox": "53", - "safari": "16.3", - "node": "6", - "deno": "1", - "ios": "16.3", - "samsung": "5", - "opera_mobile": "36", - "electron": "0.37" - }, - "transform-async-generator-functions": { - "chrome": "63", - "opera": "50", - "edge": "79", - "firefox": "57", - "safari": "12", - "node": "10", - "deno": "1", - "ios": "12", - "samsung": "8", - "opera_mobile": "46", - "electron": "3.0" - }, - "proposal-async-generator-functions": { - "chrome": "63", - "opera": "50", - "edge": "79", - "firefox": "57", - "safari": "12", - "node": "10", - "deno": "1", - "ios": "12", - "samsung": "8", - "opera_mobile": "46", - "electron": "3.0" - }, - "transform-object-rest-spread": { - "chrome": "60", - "opera": "47", - "edge": "79", - "firefox": "55", - "safari": "11.1", - "node": "8.3", - "deno": "1", - "ios": "11.3", - "samsung": "8", - "opera_mobile": "44", - "electron": "2.0" - }, - "proposal-object-rest-spread": { - "chrome": "60", - "opera": "47", - "edge": "79", - "firefox": "55", - "safari": "11.1", - "node": "8.3", - "deno": "1", - "ios": "11.3", - "samsung": "8", - "opera_mobile": "44", - "electron": "2.0" - }, - "transform-dotall-regex": { - "chrome": "62", - "opera": "49", - "edge": "79", - "firefox": "78", - "safari": "11.1", - "node": "8.10", - "deno": "1", - "ios": "11.3", - "samsung": "8", - "opera_mobile": "46", - "electron": "3.0" - }, - "transform-unicode-property-regex": { - "chrome": "64", - "opera": "51", - "edge": "79", - "firefox": "78", - "safari": "11.1", - "node": "10", - "deno": "1", - "ios": "11.3", - "samsung": "9", - "opera_mobile": "47", - "electron": "3.0" - }, - "proposal-unicode-property-regex": { - "chrome": "64", - "opera": "51", - "edge": "79", - "firefox": "78", - "safari": "11.1", - "node": "10", - "deno": "1", - "ios": "11.3", - "samsung": "9", - "opera_mobile": "47", - "electron": "3.0" - }, - "transform-named-capturing-groups-regex": { - "chrome": "64", - "opera": "51", - "edge": "79", - "firefox": "78", - "safari": "11.1", - "node": "10", - "deno": "1", - "ios": "11.3", - "samsung": "9", - "opera_mobile": "47", - "electron": "3.0" - }, - "transform-async-to-generator": { - "chrome": "55", - "opera": "42", - "edge": "15", - "firefox": "52", - "safari": "11", - "node": "7.6", - "deno": "1", - "ios": "11", - "samsung": "6", - "opera_mobile": "42", - "electron": "1.6" - }, - "transform-exponentiation-operator": { - "chrome": "52", - "opera": "39", - "edge": "14", - "firefox": "52", - "safari": "10.1", - "node": "7", - "deno": "1", - "ios": "10.3", - "samsung": "6", - "rhino": "1.7.14", - "opera_mobile": "41", - "electron": "1.3" - }, - "transform-template-literals": { - "chrome": "41", - "opera": "28", - "edge": "13", - "firefox": "34", - "safari": "13", - "node": "4", - "deno": "1", - "ios": "13", - "samsung": "3.4", - "opera_mobile": "28", - "electron": "0.21" - }, - "transform-literals": { - "chrome": "44", - "opera": "31", - "edge": "12", - "firefox": "53", - "safari": "9", - "node": "4", - "deno": "1", - "ios": "9", - "samsung": "4", - "opera_mobile": "32", - "electron": "0.30" - }, - "transform-function-name": { - "chrome": "51", - "opera": "38", - "edge": "79", - "firefox": "53", - "safari": "10", - "node": "6.5", - "deno": "1", - "ios": "10", - "samsung": "5", - "opera_mobile": "41", - "electron": "1.2" - }, - "transform-arrow-functions": { - "chrome": "47", - "opera": "34", - "edge": "13", - "firefox": "43", - "safari": "10", - "node": "6", - "deno": "1", - "ios": "10", - "samsung": "5", - "rhino": "1.7.13", - "opera_mobile": "34", - "electron": "0.36" - }, - "transform-block-scoped-functions": { - "chrome": "41", - "opera": "28", - "edge": "12", - "firefox": "46", - "safari": "10", - "node": "4", - "deno": "1", - "ie": "11", - "ios": "10", - "samsung": "3.4", - "opera_mobile": "28", - "electron": "0.21" - }, - "transform-classes": { - "chrome": "46", - "opera": "33", - "edge": "13", - "firefox": "45", - "safari": "10", - "node": "5", - "deno": "1", - "ios": "10", - "samsung": "5", - "opera_mobile": "33", - "electron": "0.36" - }, - "transform-object-super": { - "chrome": "46", - "opera": "33", - "edge": "13", - "firefox": "45", - "safari": "10", - "node": "5", - "deno": "1", - "ios": "10", - "samsung": "5", - "opera_mobile": "33", - "electron": "0.36" - }, - "transform-shorthand-properties": { - "chrome": "43", - "opera": "30", - "edge": "12", - "firefox": "33", - "safari": "9", - "node": "4", - "deno": "1", - "ios": "9", - "samsung": "4", - "rhino": "1.7.14", - "opera_mobile": "30", - "electron": "0.27" - }, - "transform-duplicate-keys": { - "chrome": "42", - "opera": "29", - "edge": "12", - "firefox": "34", - "safari": "9", - "node": "4", - "deno": "1", - "ios": "9", - "samsung": "3.4", - "opera_mobile": "29", - "electron": "0.25" - }, - "transform-computed-properties": { - "chrome": "44", - "opera": "31", - "edge": "12", - "firefox": "34", - "safari": "7.1", - "node": "4", - "deno": "1", - "ios": "8", - "samsung": "4", - "opera_mobile": "32", - "electron": "0.30" - }, - "transform-for-of": { - "chrome": "51", - "opera": "38", - "edge": "15", - "firefox": "53", - "safari": "10", - "node": "6.5", - "deno": "1", - "ios": "10", - "samsung": "5", - "opera_mobile": "41", - "electron": "1.2" - }, - "transform-sticky-regex": { - "chrome": "49", - "opera": "36", - "edge": "13", - "firefox": "3", - "safari": "10", - "node": "6", - "deno": "1", - "ios": "10", - "samsung": "5", - "opera_mobile": "36", - "electron": "0.37" - }, - "transform-unicode-escapes": { - "chrome": "44", - "opera": "31", - "edge": "12", - "firefox": "53", - "safari": "9", - "node": "4", - "deno": "1", - "ios": "9", - "samsung": "4", - "opera_mobile": "32", - "electron": "0.30" - }, - "transform-unicode-regex": { - "chrome": "50", - "opera": "37", - "edge": "13", - "firefox": "46", - "safari": "12", - "node": "6", - "deno": "1", - "ios": "12", - "samsung": "5", - "opera_mobile": "37", - "electron": "1.1" - }, - "transform-spread": { - "chrome": "46", - "opera": "33", - "edge": "13", - "firefox": "45", - "safari": "10", - "node": "5", - "deno": "1", - "ios": "10", - "samsung": "5", - "opera_mobile": "33", - "electron": "0.36" - }, - "transform-destructuring": { - "chrome": "51", - "opera": "38", - "edge": "15", - "firefox": "53", - "safari": "10", - "node": "6.5", - "deno": "1", - "ios": "10", - "samsung": "5", - "opera_mobile": "41", - "electron": "1.2" - }, - "transform-block-scoping": { - "chrome": "50", - "opera": "37", - "edge": "14", - "firefox": "53", - "safari": "11", - "node": "6", - "deno": "1", - "ios": "11", - "samsung": "5", - "opera_mobile": "37", - "electron": "1.1" - }, - "transform-typeof-symbol": { - "chrome": "38", - "opera": "25", - "edge": "12", - "firefox": "36", - "safari": "9", - "node": "0.12", - "deno": "1", - "ios": "9", - "samsung": "3", - "rhino": "1.7.13", - "opera_mobile": "25", - "electron": "0.20" - }, - "transform-new-target": { - "chrome": "46", - "opera": "33", - "edge": "14", - "firefox": "41", - "safari": "10", - "node": "5", - "deno": "1", - "ios": "10", - "samsung": "5", - "opera_mobile": "33", - "electron": "0.36" - }, - "transform-regenerator": { - "chrome": "50", - "opera": "37", - "edge": "13", - "firefox": "53", - "safari": "10", - "node": "6", - "deno": "1", - "ios": "10", - "samsung": "5", - "opera_mobile": "37", - "electron": "1.1" - }, - "transform-member-expression-literals": { - "chrome": "7", - "opera": "12", - "edge": "12", - "firefox": "2", - "safari": "5.1", - "node": "0.4", - "deno": "1", - "ie": "9", - "android": "4", - "ios": "6", - "phantom": "1.9", - "samsung": "1", - "rhino": "1.7.13", - "opera_mobile": "12", - "electron": "0.20" - }, - "transform-property-literals": { - "chrome": "7", - "opera": "12", - "edge": "12", - "firefox": "2", - "safari": "5.1", - "node": "0.4", - "deno": "1", - "ie": "9", - "android": "4", - "ios": "6", - "phantom": "1.9", - "samsung": "1", - "rhino": "1.7.13", - "opera_mobile": "12", - "electron": "0.20" - }, - "transform-reserved-words": { - "chrome": "13", - "opera": "10.50", - "edge": "12", - "firefox": "2", - "safari": "3.1", - "node": "0.6", - "deno": "1", - "ie": "9", - "android": "4.4", - "ios": "6", - "phantom": "1.9", - "samsung": "1", - "rhino": "1.7.13", - "opera_mobile": "10.1", - "electron": "0.20" - }, - "transform-export-namespace-from": { - "chrome": "72", - "deno": "1.0", - "edge": "79", - "firefox": "80", - "node": "13.2", - "opera": "60", - "opera_mobile": "51", - "safari": "14.1", - "ios": "14.5", - "samsung": "11.0", - "android": "72", - "electron": "5.0" - }, - "proposal-export-namespace-from": { - "chrome": "72", - "deno": "1.0", - "edge": "79", - "firefox": "80", - "node": "13.2", - "opera": "60", - "opera_mobile": "51", - "safari": "14.1", - "ios": "14.5", - "samsung": "11.0", - "android": "72", - "electron": "5.0" - } -} diff --git a/crates/oxc_transformer/src/options/babel/env/data/esbuild/features.json b/crates/oxc_transformer/src/options/babel/env/data/esbuild/features.json deleted file mode 100644 index be61049afa459..0000000000000 --- a/crates/oxc_transformer/src/options/babel/env/data/esbuild/features.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "esbuild-regexp-lookbehind-assertions": { - "chrome": "62", - "deno": "1.0", - "edge": "79", - "firefox": "78", - "hermes": "0.7", - "ios": "16.4", - "node": "8.10", - "opera": "49", - "safari": "16.4" - }, - "esbuild-regexp-match-indices": { - "chrome": "90", - "deno": "1.8", - "edge": "90", - "firefox": "88", - "ios": "15.0", - "node": "16.0", - "opera": "76", - "safari": "15.0" - } -} diff --git a/crates/oxc_transformer/src/options/babel/env/data/mod.rs b/crates/oxc_transformer/src/options/babel/env/data/mod.rs deleted file mode 100644 index 6afc0149e0ec4..0000000000000 --- a/crates/oxc_transformer/src/options/babel/env/data/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::sync::OnceLock; - -use rustc_hash::FxHashMap; - -use super::EngineTargets; - -/// Reference: -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(); - - map.extend( - serde_json::from_str::>>(include_str!( - "./esbuild/features.json" - )) - .unwrap(), - ); - - map.into_iter() - .map(|(feature, mut versions)| { - let version = versions.get("safari"); - if version.is_some_and(|v| v == "tp") { - versions.remove("safari"); - } - let versions = versions.into_iter().collect::>(); - (feature, EngineTargets::parse_versions(versions)) - }) - .collect() - }) -} diff --git a/crates/oxc_transformer/src/options/babel/env/mod.rs b/crates/oxc_transformer/src/options/babel/env/mod.rs index 2bcb91bf963e7..82318787503cc 100644 --- a/crates/oxc_transformer/src/options/babel/env/mod.rs +++ b/crates/oxc_transformer/src/options/babel/env/mod.rs @@ -1,11 +1,13 @@ -mod data; mod targets; use serde::Deserialize; -pub use self::{data::features, targets::BabelTargets}; +pub use self::targets::BabelTargets; -use crate::options::EngineTargets; +use crate::options::{ + es_features::{features, ESFeature}, + EngineTargets, +}; fn default_as_true() -> bool { true @@ -59,7 +61,7 @@ pub struct BabelEnvOptions { } impl BabelEnvOptions { - pub fn can_enable_plugin(&self, plugin_name: &str) -> bool { - self.targets.should_enable(&features()[plugin_name]) + pub fn can_enable(&self, feature: ESFeature) -> bool { + self.targets.should_enable(&features()[&feature]) } } diff --git a/crates/oxc_transformer/src/options/babel/env/targets.rs b/crates/oxc_transformer/src/options/babel/env/targets.rs index d9998bb5c6f87..fc51b4a7b928c 100644 --- a/crates/oxc_transformer/src/options/babel/env/targets.rs +++ b/crates/oxc_transformer/src/options/babel/env/targets.rs @@ -70,7 +70,7 @@ impl TryFrom for EngineTargets { }; match Version::parse(&v) { Ok(version) => { - engine_targets.targets.insert(engine, version); + engine_targets.insert(engine, version); } Err(err) => { return Err(oxc_diagnostics::Error::msg(format!( diff --git a/crates/oxc_transformer/src/options/engine_targets.rs b/crates/oxc_transformer/src/options/engine_targets.rs index dad81a77aa1cd..c483014e6df54 100644 --- a/crates/oxc_transformer/src/options/engine_targets.rs +++ b/crates/oxc_transformer/src/options/engine_targets.rs @@ -1,4 +1,8 @@ -use std::str::FromStr; +use std::{ + fmt::Debug, + ops::{Deref, DerefMut}, + str::FromStr, +}; use browserslist::Version; use rustc_hash::FxHashMap; @@ -27,6 +31,8 @@ pub enum Engine { Electron, // TODO: how to handle? There is a `op_mob` key below. OperaMobile, + // TODO: + Android, } impl FromStr for Engine { @@ -48,6 +54,7 @@ impl FromStr for Engine { "samsung" => Ok(Self::Samsung), "electron" => Ok(Self::Electron), "opera_mobile" => Ok(Self::OperaMobile), + "android" => Ok(Self::Android), _ => Err(()), } } @@ -56,11 +63,25 @@ impl FromStr for Engine { /// A map of engine names to minimum supported versions. #[derive(Debug, Default, Clone, Deserialize)] #[serde(try_from = "BabelTargets")] -pub struct EngineTargets { - pub(crate) targets: FxHashMap, +pub struct EngineTargets(FxHashMap); + +impl Deref for EngineTargets { + type Target = FxHashMap; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for EngineTargets { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } impl EngineTargets { + pub fn new(map: FxHashMap) -> Self { + Self(map) + } /// # Errors /// /// * Query is invalid. @@ -70,12 +91,12 @@ impl EngineTargets { /// Returns true if all fields are [None]. pub fn is_any_target(&self) -> bool { - self.targets.is_empty() + self.0.is_empty() } pub fn should_enable(&self, engine_targets: &EngineTargets) -> bool { - for (engine, version) in &engine_targets.targets { - if let Some(v) = self.targets.get(engine) { + for (engine, version) in &engine_targets.0 { + if let Some(v) = self.0.get(engine) { if v < version { return true; } @@ -95,7 +116,7 @@ impl EngineTargets { continue; }; engine_targets - .targets + .0 .entry(engine) .and_modify(|v| { if version < *v { diff --git a/crates/oxc_transformer/src/options/env.rs b/crates/oxc_transformer/src/options/env.rs index 995f31a0a803a..a6c4cdc0d93d4 100644 --- a/crates/oxc_transformer/src/options/env.rs +++ b/crates/oxc_transformer/src/options/env.rs @@ -17,7 +17,7 @@ use crate::{ EngineTargets, }; -use super::babel::BabelEnvOptions; +use super::{babel::BabelEnvOptions, ESFeature}; #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] pub enum ESTarget { @@ -179,53 +179,46 @@ impl From for EnvOptions { impl TryFrom for EnvOptions { type Error = String; + #[allow(clippy::enum_glob_use)] /// If there are any errors in the `options.targets``, they will be returned as a list of errors. fn try_from(o: BabelEnvOptions) -> Result { + use ESFeature::*; Ok(Self { regexp: RegExpOptions { - sticky_flag: o.can_enable_plugin("transform-sticky-regex"), - unicode_flag: o.can_enable_plugin("transform-unicode-regex"), - unicode_property_escapes: o.can_enable_plugin("transform-unicode-property-regex"), - dot_all_flag: o.can_enable_plugin("transform-dotall-regex"), - named_capture_groups: o.can_enable_plugin("transform-named-capturing-groups-regex"), - look_behind_assertions: o.can_enable_plugin("esbuild-regexp-lookbehind-assertions"), - match_indices: o.can_enable_plugin("esbuild-regexp-match-indices"), - set_notation: o.can_enable_plugin("transform-unicode-sets-regex"), + sticky_flag: o.can_enable(ES2015StickyRegex), + unicode_flag: o.can_enable(ES2015UnicodeRegex), + unicode_property_escapes: o.can_enable(ES2018UnicodePropertyRegex), + dot_all_flag: o.can_enable(ES2018DotallRegex), + named_capture_groups: o.can_enable(ES2018NamedCapturingGroupsRegex), + // FIXME + look_behind_assertions: false, // o.can_enable("esbuild-regexp-lookbehind-assertions"), + // FIXME + match_indices: false, // o.can_enable("esbuild-regexp-match-indices"), + set_notation: o.can_enable(ES2024UnicodeSetsRegex), }, es2015: ES2015Options { - arrow_function: o - .can_enable_plugin("transform-arrow-functions") - .then(Default::default), + arrow_function: o.can_enable(ES2015ArrowFunctions).then(Default::default), }, es2016: ES2016Options { - exponentiation_operator: o.can_enable_plugin("transform-exponentiation-operator"), - }, - es2017: ES2017Options { - async_to_generator: o.can_enable_plugin("transform-async-to-generator"), + exponentiation_operator: o.can_enable(ES2016ExponentiationOperator), }, + es2017: ES2017Options { async_to_generator: o.can_enable(ES2017AsyncToGenerator) }, es2018: ES2018Options { - object_rest_spread: o - .can_enable_plugin("transform-object-rest-spread") - .then(Default::default), - async_generator_functions: o - .can_enable_plugin("transform-async-generator-functions"), + object_rest_spread: o.can_enable(ES2018ObjectRestSpread).then(Default::default), + async_generator_functions: o.can_enable(ES2018AsyncGeneratorFunctions), }, es2019: ES2019Options { - optional_catch_binding: o.can_enable_plugin("transform-optional-catch-binding"), + optional_catch_binding: o.can_enable(ES2018OptionalCatchBinding), }, es2020: ES2020Options { - nullish_coalescing_operator: o - .can_enable_plugin("transform-nullish-coalescing-operator"), + nullish_coalescing_operator: o.can_enable(ES2020NullishCoalescingOperator), }, es2021: ES2021Options { - logical_assignment_operators: o - .can_enable_plugin("transform-logical-assignment-operators"), + logical_assignment_operators: o.can_enable(ES2020LogicalAssignmentOperators), }, es2022: ES2022Options { - class_static_block: o.can_enable_plugin("transform-class-static-block"), - class_properties: o - .can_enable_plugin("transform-class-properties") - .then(Default::default), + class_static_block: o.can_enable(ES2022ClassStaticBlock), + class_properties: o.can_enable(ES2022ClassProperties).then(Default::default), }, }) } diff --git a/crates/oxc_transformer/src/options/es_features.rs b/crates/oxc_transformer/src/options/es_features.rs new file mode 100644 index 0000000000000..4b8baa9332ae2 --- /dev/null +++ b/crates/oxc_transformer/src/options/es_features.rs @@ -0,0 +1,777 @@ +// Auto generated by `tasks/compat_data/src/lib.rs`. +#![allow(clippy::enum_glob_use)] +use super::{Engine, EngineTargets}; +use browserslist::Version; +use rustc_hash::FxHashMap; +use std::sync::OnceLock; +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub enum ESFeature { + ES5ReservedWords, + ES5PropertyLiterals, + ES5MemberExpressionLiterals, + ES2015Parameters, + ES2015Regenerator, + ES2015NewTarget, + ES2015TypeofSymbol, + ES2015BlockScoping, + ES2015Destructuring, + ES2015Spread, + ES2015UnicodeRegex, + ES2015UnicodeEscapes, + ES2015StickyRegex, + ES2015ForOf, + ES2015ComputedProperties, + ES2015DuplicateKeys, + ES2015ShorthandProperties, + ES2015ObjectSuper, + ES2015Classes, + ES2015BlockScopedFunctions, + ES2015ArrowFunctions, + ES2015FunctionName, + ES2015Literals, + ES2015TemplateLiterals, + ES2016ExponentiationOperator, + ES2017AsyncToGenerator, + ES2018NamedCapturingGroupsRegex, + ES2018UnicodePropertyRegex, + ES2018DotallRegex, + ES2018ObjectRestSpread, + ES2018AsyncGeneratorFunctions, + ES2018OptionalCatchBinding, + ES2019JsonStrings, + ES2019OptionalChaining, + ES2020NullishCoalescingOperator, + ES2020LogicalAssignmentOperators, + ES2021NumericSeparator, + ES2022PrivateMethods, + ES2022ClassProperties, + ES2022PrivatePropertyInObject, + ES2022ClassStaticBlock, + ES2024UnicodeSetsRegex, + ES2025RegexpModifiers, + ES2025DuplicateNamedCapturingGroupsRegex, +} +pub fn features() -> &'static FxHashMap { + use ESFeature::*; + use Engine::*; + static FEATURES: OnceLock> = OnceLock::new(); + FEATURES.get_or_init(|| { + FxHashMap::from_iter([ + ( + ES5ReservedWords, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(13u32, 0u32, 0u32)), + (Safari, Version(3u32, 1u32, 0u32)), + (OperaMobile, Version(10u32, 1u32, 0u32)), + (Samsung, Version(1u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 13u32)), + (Node, Version(0u32, 6u32, 0u32)), + (Ie, Version(9u32, 0u32, 0u32)), + (Firefox, Version(2u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Android, Version(4u32, 4u32, 0u32)), + (Electron, Version(0u32, 20u32, 0u32)), + (Opera, Version(10u32, 50u32, 0u32)), + (Ios, Version(6u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES5PropertyLiterals, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(7u32, 0u32, 0u32)), + (Safari, Version(5u32, 1u32, 0u32)), + (OperaMobile, Version(12u32, 0u32, 0u32)), + (Samsung, Version(1u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 13u32)), + (Node, Version(0u32, 4u32, 0u32)), + (Ie, Version(9u32, 0u32, 0u32)), + (Firefox, Version(2u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Android, Version(4u32, 0u32, 0u32)), + (Electron, Version(0u32, 20u32, 0u32)), + (Opera, Version(12u32, 0u32, 0u32)), + (Ios, Version(6u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES5MemberExpressionLiterals, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(7u32, 0u32, 0u32)), + (Safari, Version(5u32, 1u32, 0u32)), + (OperaMobile, Version(12u32, 0u32, 0u32)), + (Samsung, Version(1u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 13u32)), + (Node, Version(0u32, 4u32, 0u32)), + (Ie, Version(9u32, 0u32, 0u32)), + (Firefox, Version(2u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Android, Version(4u32, 0u32, 0u32)), + (Electron, Version(0u32, 20u32, 0u32)), + (Opera, Version(12u32, 0u32, 0u32)), + (Ios, Version(6u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES2015Parameters, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(49u32, 0u32, 0u32)), + (Safari, Version(16u32, 3u32, 0u32)), + (OperaMobile, Version(36u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(6u32, 0u32, 0u32)), + (Firefox, Version(53u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 37u32, 0u32)), + (Opera, Version(36u32, 0u32, 0u32)), + (Ios, Version(16u32, 3u32, 0u32)), + (Edge, Version(18u32, 0u32, 0u32)), + ])), + ), + ( + ES2015Regenerator, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(50u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(37u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(6u32, 0u32, 0u32)), + (Firefox, Version(53u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(1u32, 1u32, 0u32)), + (Opera, Version(37u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(13u32, 0u32, 0u32)), + ])), + ), + ( + ES2015NewTarget, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(46u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(33u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(5u32, 0u32, 0u32)), + (Firefox, Version(41u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 36u32, 0u32)), + (Opera, Version(33u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(14u32, 0u32, 0u32)), + ])), + ), + ( + ES2015TypeofSymbol, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(38u32, 0u32, 0u32)), + (Safari, Version(9u32, 0u32, 0u32)), + (OperaMobile, Version(25u32, 0u32, 0u32)), + (Samsung, Version(3u32, 0u32, 0u32)), + (Node, Version(0u32, 12u32, 0u32)), + (Rhino, Version(1u32, 7u32, 13u32)), + (Firefox, Version(36u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 20u32, 0u32)), + (Opera, Version(25u32, 0u32, 0u32)), + (Ios, Version(9u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES2015BlockScoping, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(50u32, 0u32, 0u32)), + (Safari, Version(11u32, 0u32, 0u32)), + (OperaMobile, Version(37u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(6u32, 0u32, 0u32)), + (Firefox, Version(53u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(1u32, 1u32, 0u32)), + (Opera, Version(37u32, 0u32, 0u32)), + (Ios, Version(11u32, 0u32, 0u32)), + (Edge, Version(14u32, 0u32, 0u32)), + ])), + ), + ( + ES2015Destructuring, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(51u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(41u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(6u32, 5u32, 0u32)), + (Firefox, Version(53u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(1u32, 2u32, 0u32)), + (Opera, Version(38u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(15u32, 0u32, 0u32)), + ])), + ), + ( + ES2015Spread, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(46u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(33u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(5u32, 0u32, 0u32)), + (Firefox, Version(45u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 36u32, 0u32)), + (Opera, Version(33u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(13u32, 0u32, 0u32)), + ])), + ), + ( + ES2015UnicodeRegex, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(50u32, 0u32, 0u32)), + (Safari, Version(12u32, 0u32, 0u32)), + (OperaMobile, Version(37u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(6u32, 0u32, 0u32)), + (Firefox, Version(46u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(1u32, 1u32, 0u32)), + (Opera, Version(37u32, 0u32, 0u32)), + (Ios, Version(12u32, 0u32, 0u32)), + (Edge, Version(13u32, 0u32, 0u32)), + ])), + ), + ( + ES2015UnicodeEscapes, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(44u32, 0u32, 0u32)), + (Safari, Version(9u32, 0u32, 0u32)), + (OperaMobile, Version(32u32, 0u32, 0u32)), + (Samsung, Version(4u32, 0u32, 0u32)), + (Node, Version(4u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 15u32)), + (Firefox, Version(53u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 30u32, 0u32)), + (Opera, Version(31u32, 0u32, 0u32)), + (Ios, Version(9u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES2015StickyRegex, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(49u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(36u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(6u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 15u32)), + (Firefox, Version(3u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 37u32, 0u32)), + (Opera, Version(36u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(13u32, 0u32, 0u32)), + ])), + ), + ( + ES2015ForOf, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(51u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(41u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(6u32, 5u32, 0u32)), + (Firefox, Version(53u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(1u32, 2u32, 0u32)), + (Opera, Version(38u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(15u32, 0u32, 0u32)), + ])), + ), + ( + ES2015ComputedProperties, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(44u32, 0u32, 0u32)), + (Safari, Version(7u32, 1u32, 0u32)), + (OperaMobile, Version(32u32, 0u32, 0u32)), + (Samsung, Version(4u32, 0u32, 0u32)), + (Node, Version(4u32, 0u32, 0u32)), + (Firefox, Version(34u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 30u32, 0u32)), + (Opera, Version(31u32, 0u32, 0u32)), + (Ios, Version(8u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES2015DuplicateKeys, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(42u32, 0u32, 0u32)), + (Safari, Version(9u32, 0u32, 0u32)), + (OperaMobile, Version(29u32, 0u32, 0u32)), + (Samsung, Version(3u32, 4u32, 0u32)), + (Node, Version(4u32, 0u32, 0u32)), + (Firefox, Version(34u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 25u32, 0u32)), + (Opera, Version(29u32, 0u32, 0u32)), + (Ios, Version(9u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES2015ShorthandProperties, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(43u32, 0u32, 0u32)), + (Safari, Version(9u32, 0u32, 0u32)), + (OperaMobile, Version(30u32, 0u32, 0u32)), + (Samsung, Version(4u32, 0u32, 0u32)), + (Node, Version(4u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 14u32)), + (Firefox, Version(33u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 27u32, 0u32)), + (Opera, Version(30u32, 0u32, 0u32)), + (Ios, Version(9u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES2015ObjectSuper, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(46u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(33u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(5u32, 0u32, 0u32)), + (Firefox, Version(45u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 36u32, 0u32)), + (Opera, Version(33u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(13u32, 0u32, 0u32)), + ])), + ), + ( + ES2015Classes, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(46u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(33u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(5u32, 0u32, 0u32)), + (Firefox, Version(45u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 36u32, 0u32)), + (Opera, Version(33u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(13u32, 0u32, 0u32)), + ])), + ), + ( + ES2015BlockScopedFunctions, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(41u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(28u32, 0u32, 0u32)), + (Samsung, Version(3u32, 4u32, 0u32)), + (Node, Version(4u32, 0u32, 0u32)), + (Ie, Version(11u32, 0u32, 0u32)), + (Firefox, Version(46u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 21u32, 0u32)), + (Opera, Version(28u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES2015ArrowFunctions, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(47u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(34u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(6u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 13u32)), + (Firefox, Version(43u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 36u32, 0u32)), + (Opera, Version(34u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(13u32, 0u32, 0u32)), + ])), + ), + ( + ES2015FunctionName, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(51u32, 0u32, 0u32)), + (Safari, Version(10u32, 0u32, 0u32)), + (OperaMobile, Version(41u32, 0u32, 0u32)), + (Samsung, Version(5u32, 0u32, 0u32)), + (Node, Version(6u32, 5u32, 0u32)), + (Firefox, Version(53u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(1u32, 2u32, 0u32)), + (Opera, Version(38u32, 0u32, 0u32)), + (Ios, Version(10u32, 0u32, 0u32)), + (Edge, Version(79u32, 0u32, 0u32)), + ])), + ), + ( + ES2015Literals, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(44u32, 0u32, 0u32)), + (Safari, Version(9u32, 0u32, 0u32)), + (OperaMobile, Version(32u32, 0u32, 0u32)), + (Samsung, Version(4u32, 0u32, 0u32)), + (Node, Version(4u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 15u32)), + (Firefox, Version(53u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 30u32, 0u32)), + (Opera, Version(31u32, 0u32, 0u32)), + (Ios, Version(9u32, 0u32, 0u32)), + (Edge, Version(12u32, 0u32, 0u32)), + ])), + ), + ( + ES2015TemplateLiterals, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(41u32, 0u32, 0u32)), + (Safari, Version(13u32, 0u32, 0u32)), + (OperaMobile, Version(28u32, 0u32, 0u32)), + (Samsung, Version(3u32, 4u32, 0u32)), + (Node, Version(4u32, 0u32, 0u32)), + (Firefox, Version(34u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(0u32, 21u32, 0u32)), + (Opera, Version(28u32, 0u32, 0u32)), + (Ios, Version(13u32, 0u32, 0u32)), + (Edge, Version(13u32, 0u32, 0u32)), + ])), + ), + ( + ES2016ExponentiationOperator, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(52u32, 0u32, 0u32)), + (Safari, Version(10u32, 1u32, 0u32)), + (OperaMobile, Version(41u32, 0u32, 0u32)), + (Samsung, Version(6u32, 0u32, 0u32)), + (Node, Version(7u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 14u32)), + (Firefox, Version(52u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(1u32, 3u32, 0u32)), + (Opera, Version(39u32, 0u32, 0u32)), + (Ios, Version(10u32, 3u32, 0u32)), + (Edge, Version(14u32, 0u32, 0u32)), + ])), + ), + ( + ES2017AsyncToGenerator, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(55u32, 0u32, 0u32)), + (Safari, Version(11u32, 0u32, 0u32)), + (OperaMobile, Version(42u32, 0u32, 0u32)), + (Samsung, Version(6u32, 0u32, 0u32)), + (Node, Version(7u32, 6u32, 0u32)), + (Firefox, Version(52u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(1u32, 6u32, 0u32)), + (Opera, Version(42u32, 0u32, 0u32)), + (Ios, Version(11u32, 0u32, 0u32)), + (Edge, Version(15u32, 0u32, 0u32)), + ])), + ), + ( + ES2018NamedCapturingGroupsRegex, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(64u32, 0u32, 0u32)), + (Safari, Version(11u32, 1u32, 0u32)), + (OperaMobile, Version(47u32, 0u32, 0u32)), + (Samsung, Version(9u32, 0u32, 0u32)), + (Node, Version(10u32, 0u32, 0u32)), + (Firefox, Version(78u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(3u32, 0u32, 0u32)), + (Opera, Version(51u32, 0u32, 0u32)), + (Ios, Version(11u32, 3u32, 0u32)), + (Edge, Version(79u32, 0u32, 0u32)), + ])), + ), + ( + ES2018UnicodePropertyRegex, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(64u32, 0u32, 0u32)), + (Safari, Version(11u32, 1u32, 0u32)), + (OperaMobile, Version(47u32, 0u32, 0u32)), + (Samsung, Version(9u32, 0u32, 0u32)), + (Node, Version(10u32, 0u32, 0u32)), + (Firefox, Version(78u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(3u32, 0u32, 0u32)), + (Opera, Version(51u32, 0u32, 0u32)), + (Ios, Version(11u32, 3u32, 0u32)), + (Edge, Version(79u32, 0u32, 0u32)), + ])), + ), + ( + ES2018DotallRegex, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(62u32, 0u32, 0u32)), + (Safari, Version(11u32, 1u32, 0u32)), + (OperaMobile, Version(46u32, 0u32, 0u32)), + (Samsung, Version(8u32, 0u32, 0u32)), + (Node, Version(8u32, 10u32, 0u32)), + (Rhino, Version(1u32, 7u32, 15u32)), + (Firefox, Version(78u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(3u32, 0u32, 0u32)), + (Opera, Version(49u32, 0u32, 0u32)), + (Ios, Version(11u32, 3u32, 0u32)), + (Edge, Version(79u32, 0u32, 0u32)), + ])), + ), + ( + ES2018ObjectRestSpread, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(60u32, 0u32, 0u32)), + (Safari, Version(11u32, 1u32, 0u32)), + (OperaMobile, Version(44u32, 0u32, 0u32)), + (Samsung, Version(8u32, 0u32, 0u32)), + (Node, Version(8u32, 3u32, 0u32)), + (Firefox, Version(55u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(2u32, 0u32, 0u32)), + (Opera, Version(47u32, 0u32, 0u32)), + (Ios, Version(11u32, 3u32, 0u32)), + (Edge, Version(79u32, 0u32, 0u32)), + ])), + ), + ( + ES2018AsyncGeneratorFunctions, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(63u32, 0u32, 0u32)), + (Safari, Version(12u32, 0u32, 0u32)), + (OperaMobile, Version(46u32, 0u32, 0u32)), + (Samsung, Version(8u32, 0u32, 0u32)), + (Node, Version(10u32, 0u32, 0u32)), + (Firefox, Version(57u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(3u32, 0u32, 0u32)), + (Opera, Version(50u32, 0u32, 0u32)), + (Ios, Version(12u32, 0u32, 0u32)), + (Edge, Version(79u32, 0u32, 0u32)), + ])), + ), + ( + ES2018OptionalCatchBinding, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(66u32, 0u32, 0u32)), + (Safari, Version(11u32, 1u32, 0u32)), + (OperaMobile, Version(47u32, 0u32, 0u32)), + (Samsung, Version(9u32, 0u32, 0u32)), + (Node, Version(10u32, 0u32, 0u32)), + (Firefox, Version(58u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(3u32, 0u32, 0u32)), + (Opera, Version(53u32, 0u32, 0u32)), + (Ios, Version(11u32, 3u32, 0u32)), + (Edge, Version(79u32, 0u32, 0u32)), + ])), + ), + ( + ES2019JsonStrings, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(66u32, 0u32, 0u32)), + (Safari, Version(12u32, 0u32, 0u32)), + (OperaMobile, Version(47u32, 0u32, 0u32)), + (Samsung, Version(9u32, 0u32, 0u32)), + (Node, Version(10u32, 0u32, 0u32)), + (Rhino, Version(1u32, 7u32, 14u32)), + (Firefox, Version(62u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(3u32, 0u32, 0u32)), + (Opera, Version(53u32, 0u32, 0u32)), + (Ios, Version(12u32, 0u32, 0u32)), + (Edge, Version(79u32, 0u32, 0u32)), + ])), + ), + ( + ES2019OptionalChaining, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(91u32, 0u32, 0u32)), + (Safari, Version(13u32, 1u32, 0u32)), + (OperaMobile, Version(64u32, 0u32, 0u32)), + (Samsung, Version(16u32, 0u32, 0u32)), + (Node, Version(16u32, 9u32, 0u32)), + (Firefox, Version(74u32, 0u32, 0u32)), + (Deno, Version(1u32, 9u32, 0u32)), + (Electron, Version(13u32, 0u32, 0u32)), + (Opera, Version(77u32, 0u32, 0u32)), + (Ios, Version(13u32, 4u32, 0u32)), + (Edge, Version(91u32, 0u32, 0u32)), + ])), + ), + ( + ES2020NullishCoalescingOperator, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(80u32, 0u32, 0u32)), + (Safari, Version(13u32, 1u32, 0u32)), + (OperaMobile, Version(57u32, 0u32, 0u32)), + (Samsung, Version(13u32, 0u32, 0u32)), + (Node, Version(14u32, 0u32, 0u32)), + (Firefox, Version(72u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(8u32, 0u32, 0u32)), + (Opera, Version(67u32, 0u32, 0u32)), + (Ios, Version(13u32, 4u32, 0u32)), + (Edge, Version(80u32, 0u32, 0u32)), + ])), + ), + ( + ES2020LogicalAssignmentOperators, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(85u32, 0u32, 0u32)), + (Safari, Version(14u32, 0u32, 0u32)), + (OperaMobile, Version(60u32, 0u32, 0u32)), + (Samsung, Version(14u32, 0u32, 0u32)), + (Node, Version(15u32, 0u32, 0u32)), + (Firefox, Version(79u32, 0u32, 0u32)), + (Deno, Version(1u32, 2u32, 0u32)), + (Electron, Version(10u32, 0u32, 0u32)), + (Opera, Version(71u32, 0u32, 0u32)), + (Ios, Version(14u32, 0u32, 0u32)), + (Edge, Version(85u32, 0u32, 0u32)), + ])), + ), + ( + ES2021NumericSeparator, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(75u32, 0u32, 0u32)), + (Safari, Version(13u32, 0u32, 0u32)), + (OperaMobile, Version(54u32, 0u32, 0u32)), + (Samsung, Version(11u32, 0u32, 0u32)), + (Node, Version(12u32, 5u32, 0u32)), + (Rhino, Version(1u32, 7u32, 14u32)), + (Firefox, Version(70u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(6u32, 0u32, 0u32)), + (Opera, Version(62u32, 0u32, 0u32)), + (Ios, Version(13u32, 0u32, 0u32)), + (Edge, Version(79u32, 0u32, 0u32)), + ])), + ), + ( + ES2022PrivateMethods, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(84u32, 0u32, 0u32)), + (Safari, Version(15u32, 0u32, 0u32)), + (OperaMobile, Version(60u32, 0u32, 0u32)), + (Samsung, Version(14u32, 0u32, 0u32)), + (Node, Version(14u32, 6u32, 0u32)), + (Firefox, Version(90u32, 0u32, 0u32)), + (Deno, Version(1u32, 0u32, 0u32)), + (Electron, Version(10u32, 0u32, 0u32)), + (Opera, Version(70u32, 0u32, 0u32)), + (Ios, Version(15u32, 0u32, 0u32)), + (Edge, Version(84u32, 0u32, 0u32)), + ])), + ), + ( + ES2022ClassProperties, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(98u32, 0u32, 0u32)), + (Safari, Version(16u32, 0u32, 0u32)), + (OperaMobile, Version(53u32, 0u32, 0u32)), + (Samsung, Version(11u32, 0u32, 0u32)), + (Node, Version(12u32, 0u32, 0u32)), + (Firefox, Version(90u32, 0u32, 0u32)), + (Deno, Version(1u32, 18u32, 0u32)), + (Electron, Version(17u32, 0u32, 0u32)), + (Opera, Version(84u32, 0u32, 0u32)), + (Ios, Version(16u32, 0u32, 0u32)), + (Edge, Version(98u32, 0u32, 0u32)), + ])), + ), + ( + ES2022PrivatePropertyInObject, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(91u32, 0u32, 0u32)), + (Safari, Version(15u32, 0u32, 0u32)), + (OperaMobile, Version(64u32, 0u32, 0u32)), + (Samsung, Version(16u32, 0u32, 0u32)), + (Node, Version(16u32, 9u32, 0u32)), + (Firefox, Version(90u32, 0u32, 0u32)), + (Deno, Version(1u32, 9u32, 0u32)), + (Electron, Version(13u32, 0u32, 0u32)), + (Opera, Version(77u32, 0u32, 0u32)), + (Ios, Version(15u32, 0u32, 0u32)), + (Edge, Version(91u32, 0u32, 0u32)), + ])), + ), + ( + ES2022ClassStaticBlock, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(94u32, 0u32, 0u32)), + (Safari, Version(16u32, 4u32, 0u32)), + (OperaMobile, Version(66u32, 0u32, 0u32)), + (Samsung, Version(17u32, 0u32, 0u32)), + (Node, Version(16u32, 11u32, 0u32)), + (Firefox, Version(93u32, 0u32, 0u32)), + (Deno, Version(1u32, 14u32, 0u32)), + (Electron, Version(15u32, 0u32, 0u32)), + (Opera, Version(80u32, 0u32, 0u32)), + (Ios, Version(16u32, 4u32, 0u32)), + (Edge, Version(94u32, 0u32, 0u32)), + ])), + ), + ( + ES2024UnicodeSetsRegex, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(112u32, 0u32, 0u32)), + (Safari, Version(17u32, 0u32, 0u32)), + (OperaMobile, Version(75u32, 0u32, 0u32)), + (Node, Version(20u32, 0u32, 0u32)), + (Firefox, Version(116u32, 0u32, 0u32)), + (Deno, Version(1u32, 32u32, 0u32)), + (Electron, Version(24u32, 0u32, 0u32)), + (Opera, Version(98u32, 0u32, 0u32)), + (Ios, Version(17u32, 0u32, 0u32)), + (Edge, Version(112u32, 0u32, 0u32)), + ])), + ), + ( + ES2025RegexpModifiers, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(125u32, 0u32, 0u32)), + (Edge, Version(125u32, 0u32, 0u32)), + (Electron, Version(31u32, 0u32, 0u32)), + (Opera, Version(111u32, 0u32, 0u32)), + (Node, Version(23u32, 0u32, 0u32)), + (Firefox, Version(132u32, 0u32, 0u32)), + ])), + ), + ( + ES2025DuplicateNamedCapturingGroupsRegex, + EngineTargets::new(FxHashMap::from_iter([ + (Chrome, Version(126u32, 0u32, 0u32)), + (Electron, Version(31u32, 0u32, 0u32)), + (Node, Version(23u32, 0u32, 0u32)), + (Firefox, Version(129u32, 0u32, 0u32)), + (Safari, Version(17u32, 4u32, 0u32)), + (Opera, Version(112u32, 0u32, 0u32)), + (Ios, Version(17u32, 4u32, 0u32)), + (Edge, Version(126u32, 0u32, 0u32)), + ])), + ), + ]) + }) +} diff --git a/crates/oxc_transformer/src/options/mod.rs b/crates/oxc_transformer/src/options/mod.rs index 1954ed1d6f399..32a9132d41501 100644 --- a/crates/oxc_transformer/src/options/mod.rs +++ b/crates/oxc_transformer/src/options/mod.rs @@ -3,6 +3,7 @@ pub mod babel; mod browserslist_query; mod engine_targets; mod env; +mod es_features; use std::path::PathBuf; @@ -27,8 +28,9 @@ use crate::{ pub use self::{ browserslist_query::BrowserslistQuery, - engine_targets::EngineTargets, + engine_targets::{Engine, EngineTargets}, env::{ESTarget, EnvOptions}, + es_features::ESFeature, }; use self::babel::BabelOptions; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6bf35630fd0a..6d2397522c9e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,7 +68,11 @@ importers: npm/oxc-types: {} - npm/oxc-wasm: {} + npm/oxc-wasm: + dependencies: + '@oxc-project/types': + specifier: workspace:^ + version: link:../oxc-types npm/oxlint: {} diff --git a/tasks/compat_data/Cargo.toml b/tasks/compat_data/Cargo.toml index 272aa18fa4384..1fc97ec1dab03 100644 --- a/tasks/compat_data/Cargo.toml +++ b/tasks/compat_data/Cargo.toml @@ -11,3 +11,14 @@ workspace = true [lib] test = false doctest = false + +[dependencies] +oxc_tasks_common = { workspace = true } +oxc_transformer = { workspace = true } + +prettyplease = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +syn = { workspace = true, features = ["parsing"] } diff --git a/tasks/compat_data/build.js b/tasks/compat_data/build.js index b4e11880895e2..5751a371105f4 100644 --- a/tasks/compat_data/build.js +++ b/tasks/compat_data/build.js @@ -7,6 +7,7 @@ const parseEnvsVersions = require('./compat-table/build-utils/parse-envs-version const interpolateAllResults = require('./compat-table/build-utils/interpolate-all-results'); const compareVersions = require('./compat-table/build-utils/compare-versions'); const { addElectronSupportFromChromium } = require('./chromium-to-electron'); +const esFeatures = require(`./es-features`); const environments = [ 'chrome', @@ -95,78 +96,24 @@ const expandFeatures = features => .filter(name => name === feat || name.startsWith(feat + ' / ')); }); -const generateData = (environments, features) => { - const data = {}; - - const normalized = {}; - for (const [key, options] of Object.entries(features)) { - if (options.overwrite) { - if (!options.replaces || options.features) { - throw new Error( - `.overwrite is only supported when using .replace and not defining .features (${key})`, - ); - } - options.features = features[options.replaces].features; - } - if (!options.features) { - normalized[key] = { - features: expandFeatures([options]), - }; - } else { - normalized[key] = { - ...options, - features: expandFeatures(options.features), - }; - } - } - - const overlapping = {}; - - // Apply bugfixes - for ( - const [key, { features, replaces, overwrite }] of Object.entries( - normalized, - ) - ) { - if (replaces) { - if (normalized[replaces].replaces) { - throw new Error(`Transitive replacement is not supported (${key})`); - } - - if (overwrite) { - normalized[key] = { - features: normalized[replaces].features, - overwrite, - }; - } else { - normalized[replaces].features = normalized[replaces].features.filter( - feat => !features.includes(feat), - ); - } - - if (!overlapping[replaces]) overlapping[replaces] = []; - overlapping[replaces].push(key); - } - } - - // eslint-disable-next-line prefer-const - for (let [key, options] of Object.entries(normalized)) { - const plugin = {}; - +const generateData = (environments, items) => { + for (const item of items) { + const targets = {}; environments.forEach(env => { - const version = getLowestImplementedVersion(options, env); - if (version) plugin[env] = version; + const version = getLowestImplementedVersion({ + features: expandFeatures(item.features), + }, env); + if (version) targets[env] = version; }); - addElectronSupportFromChromium(plugin); - - if (options.overwrite) Object.assign(plugin, options.overwrite); + addElectronSupportFromChromium(targets); - data[key] = plugin; + item.targets = targets; } - return { data, overlapping }; + console.log(items); + return items; }; -const { data } = generateData(environments, require(`./plugin-features`)); +const items = generateData(environments, esFeatures); -fs.writeFileSync('./data.json', JSON.stringify(data, null, 2)); +fs.writeFileSync('./data.json', JSON.stringify(items, null, 2)); diff --git a/tasks/compat_data/data.json b/tasks/compat_data/data.json new file mode 100644 index 0000000000000..166833d0aecce --- /dev/null +++ b/tasks/compat_data/data.json @@ -0,0 +1,970 @@ +[ + { + "name": "ReservedWords", + "es": "ES5", + "babel": "transform-reserved-words", + "features": [ + "Miscellaneous / Unreserved words" + ], + "targets": { + "chrome": "13", + "opera": "10.50", + "edge": "12", + "firefox": "2", + "safari": "3.1", + "node": "0.6", + "deno": "1", + "ie": "9", + "android": "4.4", + "ios": "6", + "samsung": "1", + "rhino": "1.7.13", + "opera_mobile": "10.1", + "electron": "0.20" + } + }, + { + "name": "PropertyLiterals", + "es": "ES5", + "babel": "transform-property-literals", + "features": [ + "Object/array literal extensions / Reserved words as property names" + ], + "targets": { + "chrome": "7", + "opera": "12", + "edge": "12", + "firefox": "2", + "safari": "5.1", + "node": "0.4", + "deno": "1", + "ie": "9", + "android": "4", + "ios": "6", + "samsung": "1", + "rhino": "1.7.13", + "opera_mobile": "12", + "electron": "0.20" + } + }, + { + "name": "MemberExpressionLiterals", + "es": "ES5", + "babel": "transform-member-expression-literals", + "features": [ + "Object/array literal extensions / Reserved words as property names" + ], + "targets": { + "chrome": "7", + "opera": "12", + "edge": "12", + "firefox": "2", + "safari": "5.1", + "node": "0.4", + "deno": "1", + "ie": "9", + "android": "4", + "ios": "6", + "samsung": "1", + "rhino": "1.7.13", + "opera_mobile": "12", + "electron": "0.20" + } + }, + { + "name": "Parameters", + "babel": "transform-parameters", + "features": [ + "default function parameters", + "rest parameters", + "destructuring, parameters / aliased defaults, arrow function", + "destructuring, parameters / shorthand defaults, arrow function", + "destructuring, parameters / duplicate identifier" + ], + "es": "ES2015", + "targets": { + "chrome": "49", + "opera": "36", + "edge": "18", + "firefox": "53", + "safari": "16.3", + "node": "6", + "deno": "1", + "ios": "16.3", + "samsung": "5", + "opera_mobile": "36", + "electron": "0.37" + } + }, + { + "name": "Regenerator", + "babel": "transform-regenerator", + "features": [ + "generators" + ], + "es": "ES2015", + "targets": { + "chrome": "50", + "opera": "37", + "edge": "13", + "firefox": "53", + "safari": "10", + "node": "6", + "deno": "1", + "ios": "10", + "samsung": "5", + "opera_mobile": "37", + "electron": "1.1" + } + }, + { + "name": "NewTarget", + "babel": "transform-new-target", + "features": [ + "new.target", + "arrow functions / lexical \"new.target\" binding" + ], + "es": "ES2015", + "targets": { + "chrome": "46", + "opera": "33", + "edge": "14", + "firefox": "41", + "safari": "10", + "node": "5", + "deno": "1", + "ios": "10", + "samsung": "5", + "opera_mobile": "33", + "electron": "0.36" + } + }, + { + "name": "TypeofSymbol", + "babel": "transform-typeof-symbol", + "features": [ + "Symbol / typeof support" + ], + "es": "ES2015", + "targets": { + "chrome": "38", + "opera": "25", + "edge": "12", + "firefox": "36", + "safari": "9", + "node": "0.12", + "deno": "1", + "ios": "9", + "samsung": "3", + "rhino": "1.7.13", + "opera_mobile": "25", + "electron": "0.20" + } + }, + { + "name": "BlockScoping", + "babel": "transform-block-scoping", + "features": [ + "const", + "let", + "generators" + ], + "es": "ES2015", + "targets": { + "chrome": "50", + "opera": "37", + "edge": "14", + "firefox": "53", + "safari": "11", + "node": "6", + "deno": "1", + "ios": "11", + "samsung": "5", + "opera_mobile": "37", + "electron": "1.1" + } + }, + { + "name": "Destructuring", + "babel": "transform-destructuring", + "features": [ + "destructuring, assignment", + "destructuring, declarations" + ], + "es": "ES2015", + "targets": { + "chrome": "51", + "opera": "38", + "edge": "15", + "firefox": "53", + "safari": "10", + "node": "6.5", + "deno": "1", + "ios": "10", + "samsung": "5", + "opera_mobile": "41", + "electron": "1.2" + } + }, + { + "name": "Spread", + "babel": "transform-spread", + "features": [ + "spread syntax for iterable objects", + "class", + "super" + ], + "es": "ES2015", + "targets": { + "chrome": "46", + "opera": "33", + "edge": "13", + "firefox": "45", + "safari": "10", + "node": "5", + "deno": "1", + "ios": "10", + "samsung": "5", + "opera_mobile": "33", + "electron": "0.36" + } + }, + { + "name": "UnicodeRegex", + "babel": "transform-unicode-regex", + "features": [ + "RegExp \"y\" and \"u\" flags / \"u\" flag, case folding", + "RegExp \"y\" and \"u\" flags / \"u\" flag, Unicode code point escapes", + "RegExp \"y\" and \"u\" flags / \"u\" flag, non-BMP Unicode characters", + "RegExp \"y\" and \"u\" flags / \"u\" flag" + ], + "es": "ES2015", + "targets": { + "chrome": "50", + "opera": "37", + "edge": "13", + "firefox": "46", + "safari": "12", + "node": "6", + "deno": "1", + "ios": "12", + "samsung": "5", + "opera_mobile": "37", + "electron": "1.1" + } + }, + { + "name": "UnicodeEscapes", + "babel": "transform-unicode-escapes", + "features": [ + "Unicode code point escapes" + ], + "es": "ES2015", + "targets": { + "chrome": "44", + "opera": "31", + "edge": "12", + "firefox": "53", + "safari": "9", + "node": "4", + "deno": "1", + "ios": "9", + "samsung": "4", + "rhino": "1.7.15", + "opera_mobile": "32", + "electron": "0.30" + } + }, + { + "name": "StickyRegex", + "babel": "transform-sticky-regex", + "features": [ + "RegExp \"y\" and \"u\" flags / \"y\" flag, lastIndex", + "RegExp \"y\" and \"u\" flags / \"y\" flag" + ], + "es": "ES2015", + "targets": { + "chrome": "49", + "opera": "36", + "edge": "13", + "firefox": "3", + "safari": "10", + "node": "6", + "deno": "1", + "ios": "10", + "samsung": "5", + "rhino": "1.7.15", + "opera_mobile": "36", + "electron": "0.37" + } + }, + { + "name": "ForOf", + "babel": "transform-for-of", + "features": [ + "for..of loops" + ], + "es": "ES2015", + "targets": { + "chrome": "51", + "opera": "38", + "edge": "15", + "firefox": "53", + "safari": "10", + "node": "6.5", + "deno": "1", + "ios": "10", + "samsung": "5", + "opera_mobile": "41", + "electron": "1.2" + } + }, + { + "name": "ComputedProperties", + "babel": "transform-computed-properties", + "features": [ + "object literal extensions / computed properties" + ], + "es": "ES2015", + "targets": { + "chrome": "44", + "opera": "31", + "edge": "12", + "firefox": "34", + "safari": "7.1", + "node": "4", + "deno": "1", + "ios": "8", + "samsung": "4", + "opera_mobile": "32", + "electron": "0.30" + } + }, + { + "name": "DuplicateKeys", + "babel": "transform-duplicate-keys", + "features": [ + "miscellaneous / duplicate property names in strict mode" + ], + "es": "ES2015", + "targets": { + "chrome": "42", + "opera": "29", + "edge": "12", + "firefox": "34", + "safari": "9", + "node": "4", + "deno": "1", + "ios": "9", + "samsung": "3.4", + "opera_mobile": "29", + "electron": "0.25" + } + }, + { + "name": "ShorthandProperties", + "babel": "transform-shorthand-properties", + "features": [ + "object literal extensions / shorthand properties" + ], + "es": "ES2015", + "targets": { + "chrome": "43", + "opera": "30", + "edge": "12", + "firefox": "33", + "safari": "9", + "node": "4", + "deno": "1", + "ios": "9", + "samsung": "4", + "rhino": "1.7.14", + "opera_mobile": "30", + "electron": "0.27" + } + }, + { + "name": "ObjectSuper", + "babel": "transform-object-super", + "features": [ + "super" + ], + "es": "ES2015", + "targets": { + "chrome": "46", + "opera": "33", + "edge": "13", + "firefox": "45", + "safari": "10", + "node": "5", + "deno": "1", + "ios": "10", + "samsung": "5", + "opera_mobile": "33", + "electron": "0.36" + } + }, + { + "name": "Classes", + "babel": "transform-classes", + "features": [ + "class", + "super", + "arrow functions / lexical \"super\" binding in constructors", + "arrow functions / lexical \"super\" binding in methods" + ], + "es": "ES2015", + "targets": { + "chrome": "46", + "opera": "33", + "edge": "13", + "firefox": "45", + "safari": "10", + "node": "5", + "deno": "1", + "ios": "10", + "samsung": "5", + "opera_mobile": "33", + "electron": "0.36" + } + }, + { + "name": "BlockScopedFunctions", + "babel": "transform-block-scoped-functions", + "features": [ + "block-level function declaration" + ], + "es": "ES2015", + "targets": { + "chrome": "41", + "opera": "28", + "edge": "12", + "firefox": "46", + "safari": "10", + "node": "4", + "deno": "1", + "ie": "11", + "ios": "10", + "samsung": "3.4", + "opera_mobile": "28", + "electron": "0.21" + } + }, + { + "name": "ArrowFunctions", + "babel": "transform-arrow-functions", + "features": [ + "arrow functions / 0 parameters", + "arrow functions / 1 parameter, no brackets", + "arrow functions / multiple parameters", + "arrow functions / lexical \"this\" binding", + "arrow functions / \"this\" unchanged by call or apply", + "arrow functions / can't be bound, can be curried", + "arrow functions / lexical \"arguments\" binding", + "arrow functions / no line break between params and =>", + "arrow functions / correct precedence", + "arrow functions / no \"prototype\" property" + ], + "es": "ES2015", + "targets": { + "chrome": "47", + "opera": "34", + "edge": "13", + "firefox": "43", + "safari": "10", + "node": "6", + "deno": "1", + "ios": "10", + "samsung": "5", + "rhino": "1.7.13", + "opera_mobile": "34", + "electron": "0.36" + } + }, + { + "name": "FunctionName", + "babel": "transform-function-name", + "features": [ + "function \"name\" property" + ], + "es": "ES2015", + "targets": { + "chrome": "51", + "opera": "38", + "edge": "79", + "firefox": "53", + "safari": "10", + "node": "6.5", + "deno": "1", + "ios": "10", + "samsung": "5", + "opera_mobile": "41", + "electron": "1.2" + } + }, + { + "name": "Literals", + "babel": "transform-literals", + "features": [ + "Unicode code point escapes" + ], + "es": "ES2015", + "targets": { + "chrome": "44", + "opera": "31", + "edge": "12", + "firefox": "53", + "safari": "9", + "node": "4", + "deno": "1", + "ios": "9", + "samsung": "4", + "rhino": "1.7.15", + "opera_mobile": "32", + "electron": "0.30" + } + }, + { + "name": "TemplateLiterals", + "babel": "transform-template-literals", + "features": [ + "template literals" + ], + "es": "ES2015", + "targets": { + "chrome": "41", + "opera": "28", + "edge": "13", + "firefox": "34", + "safari": "13", + "node": "4", + "deno": "1", + "ios": "13", + "samsung": "3.4", + "opera_mobile": "28", + "electron": "0.21" + } + }, + { + "name": "ExponentiationOperator", + "babel": "transform-exponentiation-operator", + "features": [ + "exponentiation (**) operator" + ], + "es": "ES2016", + "targets": { + "chrome": "52", + "opera": "39", + "edge": "14", + "firefox": "52", + "safari": "10.1", + "node": "7", + "deno": "1", + "ios": "10.3", + "samsung": "6", + "rhino": "1.7.14", + "opera_mobile": "41", + "electron": "1.3" + } + }, + { + "name": "AsyncToGenerator", + "babel": "transform-async-to-generator", + "features": [ + "async functions" + ], + "es": "ES2017", + "targets": { + "chrome": "55", + "opera": "42", + "edge": "15", + "firefox": "52", + "safari": "11", + "node": "7.6", + "deno": "1", + "ios": "11", + "samsung": "6", + "opera_mobile": "42", + "electron": "1.6" + } + }, + { + "name": "NamedCapturingGroupsRegex", + "babel": "transform-named-capturing-groups-regex", + "features": [ + "RegExp named capture groups" + ], + "es": "ES2018", + "targets": { + "chrome": "64", + "opera": "51", + "edge": "79", + "firefox": "78", + "safari": "11.1", + "node": "10", + "deno": "1", + "ios": "11.3", + "samsung": "9", + "opera_mobile": "47", + "electron": "3.0" + } + }, + { + "name": "UnicodePropertyRegex", + "babel": "transform-unicode-property-regex", + "features": [ + "RegExp Unicode Property Escapes / basic" + ], + "es": "ES2018", + "targets": { + "chrome": "64", + "opera": "51", + "edge": "79", + "firefox": "78", + "safari": "11.1", + "node": "10", + "deno": "1", + "ios": "11.3", + "samsung": "9", + "opera_mobile": "47", + "electron": "3.0" + } + }, + { + "name": "DotallRegex", + "babel": "transform-dotall-regex", + "features": [ + "s (dotAll) flag for regular expressions" + ], + "es": "ES2018", + "targets": { + "chrome": "62", + "opera": "49", + "edge": "79", + "firefox": "78", + "safari": "11.1", + "node": "8.10", + "deno": "1", + "ios": "11.3", + "samsung": "8", + "rhino": "1.7.15", + "opera_mobile": "46", + "electron": "3.0" + } + }, + { + "name": "ObjectRestSpread", + "babel": "transform-object-rest-spread", + "features": [ + "object rest/spread properties" + ], + "es": "ES2018", + "targets": { + "chrome": "60", + "opera": "47", + "edge": "79", + "firefox": "55", + "safari": "11.1", + "node": "8.3", + "deno": "1", + "ios": "11.3", + "samsung": "8", + "opera_mobile": "44", + "electron": "2.0" + } + }, + { + "name": "AsyncGeneratorFunctions", + "babel": "transform-async-generator-functions", + "features": [ + "Asynchronous Iterators" + ], + "es": "ES2018", + "targets": { + "chrome": "63", + "opera": "50", + "edge": "79", + "firefox": "57", + "safari": "12", + "node": "10", + "deno": "1", + "ios": "12", + "samsung": "8", + "opera_mobile": "46", + "electron": "3.0" + } + }, + { + "name": "OptionalCatchBinding", + "babel": "transform-optional-catch-binding", + "features": [ + "optional catch binding" + ], + "es": "ES2018", + "targets": { + "chrome": "66", + "opera": "53", + "edge": "79", + "firefox": "58", + "safari": "11.1", + "node": "10", + "deno": "1", + "ios": "11.3", + "samsung": "9", + "opera_mobile": "47", + "electron": "3.0" + } + }, + { + "name": "JsonStrings", + "babel": "transform-json-strings", + "features": [ + "JSON superset" + ], + "es": "ES2019", + "targets": { + "chrome": "66", + "opera": "53", + "edge": "79", + "firefox": "62", + "safari": "12", + "node": "10", + "deno": "1", + "ios": "12", + "samsung": "9", + "rhino": "1.7.14", + "opera_mobile": "47", + "electron": "3.0" + } + }, + { + "name": "OptionalChaining", + "babel": "transform-optional-chaining", + "features": [ + "optional chaining operator (?.)" + ], + "es": "ES2019", + "targets": { + "chrome": "91", + "opera": "77", + "edge": "91", + "firefox": "74", + "safari": "13.1", + "node": "16.9", + "deno": "1.9", + "ios": "13.4", + "samsung": "16", + "opera_mobile": "64", + "electron": "13.0" + } + }, + { + "name": "NullishCoalescingOperator", + "babel": "transform-nullish-coalescing-operator", + "features": [ + "nullish coalescing operator (??)" + ], + "es": "ES2020", + "targets": { + "chrome": "80", + "opera": "67", + "edge": "80", + "firefox": "72", + "safari": "13.1", + "node": "14", + "deno": "1", + "ios": "13.4", + "samsung": "13", + "opera_mobile": "57", + "electron": "8.0" + } + }, + { + "name": "LogicalAssignmentOperators", + "babel": "transform-logical-assignment-operators", + "features": [ + "Logical Assignment" + ], + "es": "ES2020", + "targets": { + "chrome": "85", + "opera": "71", + "edge": "85", + "firefox": "79", + "safari": "14", + "node": "15", + "deno": "1.2", + "ios": "14", + "samsung": "14", + "opera_mobile": "60", + "electron": "10.0" + } + }, + { + "name": "NumericSeparator", + "babel": "transform-numeric-separator", + "features": [ + "numeric separators" + ], + "es": "ES2021", + "targets": { + "chrome": "75", + "opera": "62", + "edge": "79", + "firefox": "70", + "safari": "13", + "node": "12.5", + "deno": "1", + "ios": "13", + "samsung": "11", + "rhino": "1.7.14", + "opera_mobile": "54", + "electron": "6.0" + } + }, + { + "name": "PrivateMethods", + "babel": "transform-private-methods", + "features": [ + "private class methods" + ], + "es": "ES2022", + "targets": { + "chrome": "84", + "opera": "70", + "edge": "84", + "firefox": "90", + "safari": "15", + "node": "14.6", + "deno": "1", + "ios": "15", + "samsung": "14", + "opera_mobile": "60", + "electron": "10.0" + } + }, + { + "name": "ClassProperties", + "babel": "transform-class-properties", + "features": [ + "static class fields", + "instance class fields / public instance class fields", + "instance class fields / private instance class fields basic support", + "instance class fields / computed instance class fields", + "instance class fields / resolving identifier in parent scope" + ], + "es": "ES2022", + "targets": { + "chrome": "98", + "opera": "84", + "edge": "98", + "firefox": "90", + "safari": "16", + "node": "12", + "deno": "1.18", + "ios": "16", + "samsung": "11", + "opera_mobile": "53", + "electron": "17.0" + } + }, + { + "name": "PrivatePropertyInObject", + "babel": "transform-private-property-in-object", + "features": [ + "Ergonomic brand checks for private fields" + ], + "es": "ES2022", + "targets": { + "chrome": "91", + "opera": "77", + "edge": "91", + "firefox": "90", + "safari": "15", + "node": "16.9", + "deno": "1.9", + "ios": "15", + "samsung": "16", + "opera_mobile": "64", + "electron": "13.0" + } + }, + { + "name": "ClassStaticBlock", + "babel": "transform-class-static-block", + "features": [ + "Class static initialization blocks" + ], + "es": "ES2022", + "targets": { + "chrome": "94", + "opera": "80", + "edge": "94", + "firefox": "93", + "safari": "16.4", + "node": "16.11", + "deno": "1.14", + "ios": "16.4", + "samsung": "17", + "opera_mobile": "66", + "electron": "15.0" + } + }, + { + "name": "UnicodeSetsRegex", + "babel": "transform-unicode-sets-regex", + "features": [ + "RegExp `v` flag / set notations", + "RegExp `v` flag / properties of Strings", + "RegExp `v` flag / constructor supports it", + "RegExp `v` flag / shows up in flags" + ], + "es": "ES2024", + "targets": { + "chrome": "112", + "opera": "98", + "edge": "112", + "firefox": "116", + "safari": "17", + "node": "20", + "deno": "1.32", + "ios": "17", + "opera_mobile": "75", + "electron": "24.0" + } + }, + { + "name": "RegexpModifiers", + "babel": "transform-regexp-modifiers", + "features": [ + "RegExp Pattern Modifiers" + ], + "es": "ES2025", + "targets": { + "chrome": "125", + "opera": "111", + "edge": "125", + "firefox": "132", + "node": "23", + "electron": "31.0" + } + }, + { + "name": "DuplicateNamedCapturingGroupsRegex", + "babel": "transform-duplicate-named-capturing-groups-regex", + "features": [ + "Duplicate named capturing groups" + ], + "es": "ES2025", + "targets": { + "chrome": "126", + "opera": "112", + "edge": "126", + "firefox": "129", + "safari": "17.4", + "node": "23", + "ios": "17.4", + "electron": "31.0" + } + } +] diff --git a/tasks/compat_data/es-features.js b/tasks/compat_data/es-features.js new file mode 100644 index 0000000000000..25e62f3d4b99c --- /dev/null +++ b/tasks/compat_data/es-features.js @@ -0,0 +1,322 @@ +// https://github.com/babel/babel/blob/main/packages/babel-compat-data/scripts/data/plugin-features.js +// https://github.com/evanw/esbuild/blob/main/compat-table/src/index.ts + +const f = (es) => (item) => { + item.es = es; + return item; +}; + +const es5 = [ + { + name: 'ReservedWords', + es: 'ES5', + babel: 'transform-reserved-words', + features: ['Miscellaneous / Unreserved words'], + }, + { + name: 'PropertyLiterals', + es: 'ES5', + babel: 'transform-property-literals', + features: [ + 'Object/array literal extensions / Reserved words as property names', + ], + }, + { + name: 'MemberExpressionLiterals', + es: 'ES5', + babel: 'transform-member-expression-literals', + features: [ + 'Object/array literal extensions / Reserved words as property names', + ], + }, +].map(f('ES5')); + +const es2015 = [ + { + name: 'Parameters', + babel: 'transform-parameters', + features: [ + 'default function parameters', + 'rest parameters', + 'destructuring, parameters / aliased defaults, arrow function', + 'destructuring, parameters / shorthand defaults, arrow function', + 'destructuring, parameters / duplicate identifier', + ], + }, + { + name: 'Regenerator', + babel: 'transform-regenerator', + features: ['generators'], + }, + { + name: 'NewTarget', + babel: 'transform-new-target', + features: ['new.target', 'arrow functions / lexical "new.target" binding'], + }, + { + name: 'TypeofSymbol', + babel: 'transform-typeof-symbol', + features: ['Symbol / typeof support'], + }, + { + name: 'BlockScoping', + babel: 'transform-block-scoping', + features: ['const', 'let', 'generators'], + }, + { + name: 'Destructuring', + babel: 'transform-destructuring', + features: ['destructuring, assignment', 'destructuring, declarations'], + }, + { + name: 'Spread', + babel: 'transform-spread', + features: ['spread syntax for iterable objects', 'class', 'super'], + }, + { + name: 'UnicodeRegex', + babel: 'transform-unicode-regex', + features: [ + 'RegExp "y" and "u" flags / "u" flag, case folding', + 'RegExp "y" and "u" flags / "u" flag, Unicode code point escapes', + 'RegExp "y" and "u" flags / "u" flag, non-BMP Unicode characters', + 'RegExp "y" and "u" flags / "u" flag', + ], + }, + { + name: 'UnicodeEscapes', + babel: 'transform-unicode-escapes', + features: ['Unicode code point escapes'], + }, + { + name: 'StickyRegex', + babel: 'transform-sticky-regex', + features: [ + 'RegExp "y" and "u" flags / "y" flag, lastIndex', + 'RegExp "y" and "u" flags / "y" flag', + ], + }, + { + name: 'ForOf', + babel: 'transform-for-of', + features: ['for..of loops'], + }, + { + name: 'ComputedProperties', + babel: 'transform-computed-properties', + features: ['object literal extensions / computed properties'], + }, + { + name: 'DuplicateKeys', + babel: 'transform-duplicate-keys', + features: ['miscellaneous / duplicate property names in strict mode'], + }, + { + name: 'ShorthandProperties', + babel: 'transform-shorthand-properties', + features: ['object literal extensions / shorthand properties'], + }, + { + name: 'ObjectSuper', + babel: 'transform-object-super', + features: ['super'], + }, + { + name: 'Classes', + babel: 'transform-classes', + features: [ + 'class', + 'super', + 'arrow functions / lexical "super" binding in constructors', + 'arrow functions / lexical "super" binding in methods', + ], + }, + { + name: 'BlockScopedFunctions', + babel: 'transform-block-scoped-functions', + features: ['block-level function declaration'], + }, + { + name: 'ArrowFunctions', + babel: 'transform-arrow-functions', + features: [ + 'arrow functions / 0 parameters', + 'arrow functions / 1 parameter, no brackets', + 'arrow functions / multiple parameters', + 'arrow functions / lexical "this" binding', + 'arrow functions / "this" unchanged by call or apply', + "arrow functions / can't be bound, can be curried", + 'arrow functions / lexical "arguments" binding', + 'arrow functions / no line break between params and =>', + 'arrow functions / correct precedence', + 'arrow functions / no "prototype" property', + ], + }, + { + name: 'FunctionName', + babel: 'transform-function-name', + features: ['function "name" property'], + }, + { + name: 'Literals', + babel: 'transform-literals', + features: ['Unicode code point escapes'], + }, + { + name: 'TemplateLiterals', + babel: 'transform-template-literals', + features: ['template literals'], + }, +].map(f('ES2015')); + +const es2016 = [ + { + name: 'ExponentiationOperator', + babel: 'transform-exponentiation-operator', + features: ['exponentiation (**) operator'], + }, +].map(f('ES2016')); + +const es2017 = [ + { + name: 'AsyncToGenerator', + babel: 'transform-async-to-generator', + features: ['async functions'], + }, +].map(f('ES2017')); + +const es2018 = [ + { + name: 'NamedCapturingGroupsRegex', + babel: 'transform-named-capturing-groups-regex', + features: ['RegExp named capture groups'], + }, + { + name: 'UnicodePropertyRegex', + babel: 'transform-unicode-property-regex', + features: ['RegExp Unicode Property Escapes / basic'], + }, + { + name: 'DotallRegex', + babel: 'transform-dotall-regex', + features: ['s (dotAll) flag for regular expressions'], + }, + { + name: 'ObjectRestSpread', + babel: 'transform-object-rest-spread', + features: ['object rest/spread properties'], + }, + { + name: 'AsyncGeneratorFunctions', + babel: 'transform-async-generator-functions', + features: ['Asynchronous Iterators'], + }, + { + name: 'OptionalCatchBinding', + babel: 'transform-optional-catch-binding', + features: ['optional catch binding'], + }, +].map(f('ES2018')); + +const es2019 = [ + { + name: 'JsonStrings', + babel: 'transform-json-strings', + features: ['JSON superset'], + }, + { + name: 'OptionalChaining', + babel: 'transform-optional-chaining', + features: ['optional chaining operator (?.)'], + }, +].map(f('ES2019')); + +const es2020 = [ + { + name: 'NullishCoalescingOperator', + babel: 'transform-nullish-coalescing-operator', + features: ['nullish coalescing operator (??)'], + }, + { + name: 'LogicalAssignmentOperators', + babel: 'transform-logical-assignment-operators', + features: ['Logical Assignment'], + }, +].map(f('ES2020')); + +const es2021 = [ + { + name: 'NumericSeparator', + babel: 'transform-numeric-separator', + features: ['numeric separators'], + }, +].map(f('ES2021')); + +const es2022 = [ + { + name: 'PrivateMethods', + babel: 'transform-private-methods', + features: ['private class methods'], + }, + { + name: 'ClassProperties', + babel: 'transform-class-properties', + features: [ + 'static class fields', + 'instance class fields / public instance class fields', + 'instance class fields / private instance class fields basic support', + 'instance class fields / computed instance class fields', + 'instance class fields / resolving identifier in parent scope', + ], + }, + { + name: 'PrivatePropertyInObject', + babel: 'transform-private-property-in-object', + features: ['Ergonomic brand checks for private fields'], + }, + { + name: 'ClassStaticBlock', + babel: 'transform-class-static-block', + features: ['Class static initialization blocks'], + }, +].map(f('ES2022')); + +const es2024 = [ + { + name: 'UnicodeSetsRegex', + babel: 'transform-unicode-sets-regex', + features: [ + 'RegExp `v` flag / set notations', + 'RegExp `v` flag / properties of Strings', + 'RegExp `v` flag / constructor supports it', + 'RegExp `v` flag / shows up in flags', + ], + }, +].map(f('ES2024')); + +const es2025 = [ + { + name: 'RegexpModifiers', + babel: 'transform-regexp-modifiers', + features: ['RegExp Pattern Modifiers'], + }, + { + name: 'DuplicateNamedCapturingGroupsRegex', + babel: 'transform-duplicate-named-capturing-groups-regex', + features: ['Duplicate named capturing groups'], + }, +].map(f('ES2025')); + +module.exports = [ + ...es5, + ...es2015, + ...es2016, + ...es2017, + ...es2018, + ...es2019, + ...es2020, + ...es2021, + ...es2022, + ...es2024, + ...es2025, +]; diff --git a/tasks/compat_data/plugin-features.js b/tasks/compat_data/plugin-features.js deleted file mode 100644 index dd8326d025901..0000000000000 --- a/tasks/compat_data/plugin-features.js +++ /dev/null @@ -1,224 +0,0 @@ -// https://github.com/babel/babel/blob/main/packages/babel-compat-data/scripts/data/plugin-features.js - -// WARNING: Plugin ordering is important. Don't reorder this file -// without checking that it doesn't break anything. - -const es5 = { - 'transform-member-expression-literals': 'Object/array literal extensions / Reserved words as property names', - 'transform-property-literals': 'Object/array literal extensions / Reserved words as property names', - 'transform-reserved-words': 'Miscellaneous / Unreserved words', -}; - -// https://github.com/babel/babel/issues/11278 -// transform-parameters should run before object-rest-spread -const es2015Parameter = { - 'transform-parameters': { - features: [ - 'default function parameters', - 'rest parameters', - 'destructuring, parameters / aliased defaults, arrow function', - 'destructuring, parameters / shorthand defaults, arrow function', - 'destructuring, parameters / duplicate identifier', - ], - }, -}; - -const es2015 = { - 'transform-template-literals': { - features: ['template literals'], - }, - 'transform-literals': { - features: ['Unicode code point escapes'], - }, - 'transform-function-name': { - features: ['function "name" property'], - }, - 'transform-arrow-functions': { - features: [ - 'arrow functions / 0 parameters', - 'arrow functions / 1 parameter, no brackets', - 'arrow functions / multiple parameters', - 'arrow functions / lexical "this" binding', - 'arrow functions / "this" unchanged by call or apply', - "arrow functions / can't be bound, can be curried", - 'arrow functions / lexical "arguments" binding', - 'arrow functions / no line break between params and =>', - 'arrow functions / correct precedence', - 'arrow functions / no "prototype" property', - ], - }, - 'transform-block-scoped-functions': { - features: ['block-level function declaration'], - }, - 'transform-classes': { - features: [ - 'class', - 'super', - 'arrow functions / lexical "super" binding in constructors', - 'arrow functions / lexical "super" binding in methods', - ], - }, - 'transform-object-super': { - features: ['super'], - }, - 'transform-shorthand-properties': { - features: ['object literal extensions / shorthand properties'], - }, - 'transform-duplicate-keys': { - features: ['miscellaneous / duplicate property names in strict mode'], - }, - 'transform-computed-properties': { - features: ['object literal extensions / computed properties'], - }, - 'transform-for-of': { - features: ['for..of loops'], - }, - 'transform-sticky-regex': { - features: [ - 'RegExp "y" and "u" flags / "y" flag, lastIndex', - 'RegExp "y" and "u" flags / "y" flag', - ], - }, - 'transform-unicode-escapes': 'Unicode code point escapes', - 'transform-unicode-regex': { - features: [ - 'RegExp "y" and "u" flags / "u" flag, case folding', - 'RegExp "y" and "u" flags / "u" flag, Unicode code point escapes', - 'RegExp "y" and "u" flags / "u" flag, non-BMP Unicode characters', - 'RegExp "y" and "u" flags / "u" flag', - ], - }, - 'transform-spread': { - features: [ - 'spread syntax for iterable objects', - // We need to compile classes when spread is not supported, because - // we cannot compile super(...args) without also rewriting the - // "super" handling. There is a bugfix that makes it better. - 'class', - 'super', - ], - }, - 'transform-destructuring': { - features: ['destructuring, assignment', 'destructuring, declarations'], - }, - 'transform-block-scoping': { - features: [ - 'const', - 'let', - // regenerator-transform doesn't support let/const, - // so we must compile them when compiling generators. - 'generators', - ], - }, - 'transform-typeof-symbol': { - features: ['Symbol / typeof support'], - }, - 'transform-new-target': { - features: ['new.target', 'arrow functions / lexical "new.target" binding'], - }, - 'transform-regenerator': { - features: ['generators'], - }, -}; - -const es2016 = { - 'transform-exponentiation-operator': { - features: ['exponentiation (**) operator'], - }, -}; - -const es2017 = { - 'transform-async-to-generator': { - features: ['async functions'], - }, -}; - -const es2018 = { - 'transform-async-generator-functions': 'Asynchronous Iterators', - 'transform-object-rest-spread': 'object rest/spread properties', - - 'transform-dotall-regex': 's (dotAll) flag for regular expressions', - 'transform-unicode-property-regex': 'RegExp Unicode Property Escapes / basic', - 'transform-named-capturing-groups-regex': 'RegExp named capture groups', -}; - -const es2019 = { - 'transform-json-strings': 'JSON superset', - 'transform-optional-catch-binding': 'optional catch binding', -}; - -const es2020 = { - 'transform-nullish-coalescing-operator': 'nullish coalescing operator (??)', - 'transform-optional-chaining': 'optional chaining operator (?.)', -}; - -const es2021 = { - 'transform-numeric-separator': 'numeric separators', - 'transform-logical-assignment-operators': 'Logical Assignment', -}; - -const es2022 = { - 'bugfix/transform-v8-static-class-fields-redefine-readonly': { - features: ['static class fields / static class fields use [[Define]]'], - replaces: 'transform-class-properties', - }, - 'bugfix/transform-firefox-class-in-computed-class-key': { - replaces: 'transform-class-properties', - overwrite: { - // TODO: Once Firefox releases the fix, write the correct version here. - firefox: undefined, - }, - }, - 'bugfix/transform-safari-class-field-initializer-scope': { - features: ['instance class fields / resolving identifier in parent scope'], - replaces: 'transform-class-properties', - }, - 'transform-class-static-block': 'Class static initialization blocks', - 'transform-private-property-in-object': 'Ergonomic brand checks for private fields', - 'transform-class-properties': { - features: [ - 'static class fields', - 'instance class fields / public instance class fields', - 'instance class fields / private instance class fields basic support', - 'instance class fields / computed instance class fields', - 'instance class fields / resolving identifier in parent scope', - ], - }, - 'transform-private-methods': 'private class methods', -}; - -const es2024 = { - 'transform-unicode-sets-regex': { - features: [ - 'RegExp `v` flag / set notations', - 'RegExp `v` flag / properties of Strings', - 'RegExp `v` flag / constructor supports it', - 'RegExp `v` flag / shows up in flags', - ], - }, -}; - -const es2025 = { - 'transform-duplicate-named-capturing-groups-regex': 'Duplicate named capturing groups', - 'transform-regexp-modifiers': 'RegExp Pattern Modifiers', -}; - -const shippedProposal = {}; - -// Run plugins for modern features first -module.exports = Object.assign( - {}, - shippedProposal, - es2025, - es2024, - es2022, - es2021, - es2020, - es2019, - es2015Parameter, - es2018, - es2017, - es2016, - es2015, - es5, -); diff --git a/tasks/compat_data/src/lib.rs b/tasks/compat_data/src/lib.rs index 8b137891791fe..db768bda13abe 100644 --- a/tasks/compat_data/src/lib.rs +++ b/tasks/compat_data/src/lib.rs @@ -1 +1,80 @@ +use std::fs; +use oxc_tasks_common::project_root; +use oxc_transformer::EngineTargets; + +use quote::quote; +use serde::Deserialize; +use syn::Ident; + +#[derive(Debug, Deserialize)] +struct Item { + name: String, + es: String, + // babel: String, + targets: EngineTargets, +} + +impl Item { + fn es_name(&self) -> Ident { + quote::format_ident!("{}{}", self.es, self.name) + } +} + +/// # Panics +pub fn generate() { + let path = project_root().join("tasks/compat_data/data.json"); + let content = fs::read_to_string(path).unwrap(); + let items = serde_json::from_str::>(&content).unwrap(); + + let es_features = items.iter().map(Item::es_name); + + let features = items.iter().map(|item| { + let key = item.es_name(); + let targets = item.targets.iter().map(|(engine, version)| { + let engine = quote::format_ident!("{engine:?}"); + let (a, b, c) = (version.0, version.1, version.2); + quote! { + (#engine, Version(#a, #b, #c)) + } + }); + quote! { + (#key, EngineTargets::new(FxHashMap::from_iter([#(#targets),*]))) + } + }); + + let code = quote! { + #![allow(clippy::enum_glob_use)] + + use browserslist::Version; + use rustc_hash::FxHashMap; + use std::sync::OnceLock; + + use super::{Engine, EngineTargets}; + + #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] + pub enum ESFeature { + #(#es_features,)* + } + + pub fn features() -> &'static FxHashMap { + use ESFeature::*; + use Engine::*; + static FEATURES: OnceLock> = OnceLock::new(); + FEATURES.get_or_init(|| { + FxHashMap::from_iter([#(#features),*]) + }) + } + }; + + generate_file("crates/oxc_transformer/src/options/es_features.rs", code); +} + +fn generate_file(file: &str, token_stream: proc_macro2::TokenStream) { + let syntax_tree = syn::parse2(token_stream).unwrap(); + let code = format!( + "// Auto generated by `tasks/compat_data/src/lib.rs`.\n{}", + prettyplease::unparse(&syntax_tree) + ); + fs::write(project_root().join(file), code).unwrap(); +} diff --git a/tasks/compat_data/src/main.rs b/tasks/compat_data/src/main.rs index f328e4d9d04c3..c98329feb7bda 100644 --- a/tasks/compat_data/src/main.rs +++ b/tasks/compat_data/src/main.rs @@ -1 +1,5 @@ -fn main() {} +use oxc_compat_data::generate; + +fn main() { + generate(); +} diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index a0339d467778e..9bbaff25b1bd7 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: d20b314c -Passed: 78/87 +Passed: 77/87 # All Passed: * babel-plugin-transform-class-static-block @@ -12,7 +12,6 @@ Passed: 78/87 * babel-plugin-transform-arrow-functions * babel-preset-typescript * babel-plugin-transform-react-jsx-source -* regexp # babel-plugin-transform-typescript (2/9) @@ -176,3 +175,8 @@ x Output mismatch x Output mismatch +# regexp (7/8) +* all-regex-plugins-enabled-by-targets/input.js +x Output mismatch + +