oxc_transformer/es2015/arrow_functions.rs
1//! ES2015 Arrow Functions
2//!
3//! This plugin transforms arrow functions (`() => {}`) to function expressions (`function () {}`).
4//!
5//! > This plugin is included in `preset-env`, in ES2015
6//!
7//! ## Missing features
8//!
9//! Implementation is incomplete at present. Still TODO:
10//!
11//! * `spec` option.
12//! * Handle `arguments` in arrow functions.
13//! * Handle `new.target` in arrow functions.
14//! * Handle arrow function in function params (`function f(g = () => this) {}`).
15//! Babel gets this wrong: <https://babeljs.io/repl#?code_lz=GYVwdgxgLglg9mABMOcAUAPRBeRaCUOAfIlABYwDOhA3gL5A&presets=&externalPlugins=%40babel%2Fplugin-transform-arrow-functions%407.24.7>
16//! * Error on arrow functions in class properties.
17//! <https://babeljs.io/repl#?code_lz=MYGwhgzhAEDC0G8BQ1oDMD2HoF5oAoBKXAPmgBcALASwgG4kBfJIA&presets=&externalPlugins=%40babel%2Fplugin-transform-arrow-functions%407.24.7>
18//! or we can support it:
19//! `class C { x = () => this; }`
20//! -> `class C { x = (function(_this) { return () => _this; })(this); }`
21//! * Error on `super` in arrow functions.
22//! <https://babeljs.io/repl#?code_lz=MYGwhgzhAEBiD29oG8C-AoUkYCEwCdoBTADwBciA7AExgSWXWmgFsiyALeagCgEoUTZtHzsArvkrR-0ALwA-aBDEAHIvgB0AM0QBuIRgxA&presets=&externalPlugins=%40babel%2Fplugin-transform-arrow-functions%407.24.7>
23//!
24//! ## Example
25//!
26//! Input:
27//! ```js
28//! var a = () => {};
29//! var a = b => b;
30//!
31//! const double = [1, 2, 3].map(num => num * 2);
32//! console.log(double); // [2,4,6]
33//!
34//! var bob = {
35//! name: "Bob",
36//! friends: ["Sally", "Tom"],
37//! printFriends() {
38//! this.friends.forEach(f => console.log(this.name + " knows " + f));
39//! },
40//! };
41//! console.log(bob.printFriends());
42//! ```
43//!
44//! Output:
45//! ```js
46//! var a = function() {};
47//! var a = function(b) { return b; };
48//!
49//! const double = [1, 2, 3].map(function(num) {
50//! return num * 2;
51//! });
52//! console.log(double); // [2,4,6]
53//!
54//! var bob = {
55//! name: "Bob",
56//! friends: ["Sally", "Tom"],
57//! printFriends() {
58//! var _this = this;
59//! this.friends.forEach(function(f) {
60//! return console.log(_this.name + " knows " + f);
61//! });
62//! },
63//! };
64//! console.log(bob.printFriends());
65//! ```
66//!
67//! ## Options
68//!
69//! ### `spec`
70//!
71//! `boolean`, defaults to `false`.
72//!
73//! This option enables the following:
74//! * Wrap the generated function in .bind(this) and keeps uses of this inside the function as-is,
75//! instead of using a renamed this.
76//! * Add a runtime check to ensure the functions are not instantiated.
77//! * Add names to arrow functions.
78//!
79//! #### Example
80//!
81//! Using spec mode with the above example produces:
82//!
83//! ```js
84//! var _this = this;
85//!
86//! var a = function a() {
87//! babelHelpers.newArrowCheck(this, _this);
88//! }.bind(this);
89//! var a = function a(b) {
90//! babelHelpers.newArrowCheck(this, _this);
91//! return b;
92//! }.bind(this);
93//!
94//! const double = [1, 2, 3].map(
95//! function(num) {
96//! babelHelpers.newArrowCheck(this, _this);
97//! return num * 2;
98//! }.bind(this)
99//! );
100//! console.log(double); // [2,4,6]
101//!
102//! var bob = {
103//! name: "Bob",
104//! friends: ["Sally", "Tom"],
105//! printFriends() {
106//! var _this2 = this;
107//! this.friends.forEach(
108//! function(f) {
109//! babelHelpers.newArrowCheck(this, _this2);
110//! return console.log(this.name + " knows " + f);
111//! }.bind(this)
112//! );
113//! },
114//! };
115//! console.log(bob.printFriends());
116//! ```
117//!
118//! ## Implementation
119//!
120//! The implementation is placed in [`crate::common::arrow_function_converter::ArrowFunctionConverter`],
121//! which can be used in other plugins.
122//!
123//! ## References:
124//!
125//! * Babel plugin implementation: <https://github.com/babel/babel/blob/v7.26.2/packages/babel-plugin-transform-arrow-functions>
126//! * Arrow function specification: <https://tc39.es/ecma262/#sec-arrow-function-definitions>
127
128use serde::Deserialize;
129
130use oxc_traverse::Traverse;
131
132use crate::{context::TransformCtx, state::TransformState};
133
134#[derive(Debug, Default, Clone, Copy, Deserialize)]
135pub struct ArrowFunctionsOptions {
136 /// This option enables the following:
137 /// * Wrap the generated function in .bind(this) and keeps uses of this inside the function as-is, instead of using a renamed this.
138 /// * Add a runtime check to ensure the functions are not instantiated.
139 /// * Add names to arrow functions.
140 #[serde(default)]
141 pub spec: bool,
142}
143
144pub struct ArrowFunctions<'a, 'ctx> {
145 _options: ArrowFunctionsOptions,
146 _ctx: &'ctx TransformCtx<'a>,
147}
148
149impl<'a, 'ctx> ArrowFunctions<'a, 'ctx> {
150 pub fn new(options: ArrowFunctionsOptions, ctx: &'ctx TransformCtx<'a>) -> Self {
151 Self { _options: options, _ctx: ctx }
152 }
153}
154
155impl<'a> Traverse<'a, TransformState<'a>> for ArrowFunctions<'a, '_> {}