1#![allow(clippy::vec_box)]
2#![allow(clippy::boxed_local)]
3
4use serde::Deserialize;
5use swc_common::{comments::Comments, Mark};
6use swc_ecma_ast::Pass;
7use swc_ecma_compat_common::regexp::{self, regexp};
8
9pub use self::{
10 arrow::arrow, block_scoped_fn::block_scoped_functions, block_scoping::block_scoping,
11 classes::classes, computed_props::computed_properties, destructuring::destructuring,
12 duplicate_keys::duplicate_keys, for_of::for_of, function_name::function_name,
13 instanceof::instance_of, new_target::new_target, object_super::object_super,
14 parameters::parameters, shorthand_property::shorthand, spread::spread,
15 sticky_regex::sticky_regex, template_literal::template_literal, typeof_symbol::typeof_symbol,
16};
17
18mod arrow;
19mod block_scoped_fn;
20mod block_scoping;
21pub mod classes;
22pub mod computed_props;
23pub mod destructuring;
24mod duplicate_keys;
25pub mod for_of;
26mod function_name;
27pub mod generator;
28mod instanceof;
29pub mod new_target;
30mod object_super;
31pub mod parameters;
32pub mod regenerator;
33mod shorthand_property;
34pub mod spread;
35mod sticky_regex;
36pub mod template_literal;
37pub mod typeof_symbol;
38
39fn exprs(unresolved_mark: Mark) -> impl Pass {
40 (
41 arrow(unresolved_mark),
42 duplicate_keys(),
43 sticky_regex(),
44 instance_of(),
45 )
46}
47
48pub fn es2015<C>(unresolved_mark: Mark, comments: Option<C>, c: Config) -> impl Pass
58where
59 C: Comments + Clone,
60{
61 (
62 (
63 regexp(regexp::Config {
64 dot_all_regex: false,
65 has_indices: false,
66 lookbehind_assertion: false,
67 named_capturing_groups_regex: false,
68 sticky_regex: true,
69 unicode_property_regex: false,
70 unicode_regex: true,
71 unicode_sets_regex: false,
72 }),
73 block_scoped_functions(),
74 template_literal(c.template_literal),
75 classes(c.classes),
76 new_target(),
77 spread(c.spread, unresolved_mark),
78 ),
79 if !c.typescript {
81 Some(object_super())
82 } else {
83 None
84 },
85 shorthand(),
86 function_name(),
87 for_of(c.for_of),
88 parameters(c.parameters, unresolved_mark),
91 (
92 exprs(unresolved_mark),
93 typeof_symbol(c.typeof_symbol),
94 computed_properties(c.computed_props),
95 destructuring(c.destructuring),
96 block_scoping(unresolved_mark),
97 generator::generator(unresolved_mark, comments.clone()),
98 ),
99 )
100}
101
102#[derive(Debug, Clone, Default, Deserialize)]
103#[serde(rename_all = "camelCase")]
104pub struct Config {
105 #[serde(default)]
106 pub classes: classes::Config,
107
108 #[serde(flatten)]
109 pub computed_props: computed_props::Config,
110
111 #[serde(flatten)]
112 pub for_of: for_of::Config,
113
114 #[serde(flatten)]
115 pub destructuring: destructuring::Config,
116
117 #[serde(flatten)]
118 pub typeof_symbol: typeof_symbol::Config,
119
120 #[serde(flatten)]
121 pub spread: spread::Config,
122
123 #[serde(default)]
124 pub regenerator: regenerator::Config,
125
126 #[serde(default)]
127 pub template_literal: template_literal::Config,
128
129 #[serde(default)]
130 pub parameters: parameters::Config,
131
132 #[serde(default)]
133 pub typescript: bool,
134}
135
136#[cfg(test)]
137mod tests {
138 use swc_ecma_transforms_base::resolver;
139 use swc_ecma_transforms_testing::{test, test_exec};
140
141 use super::*;
142
143 test!(
144 ::swc_ecma_parser::Syntax::default(),
145 |t| es2015(
146 Mark::fresh(Mark::root()),
147 Some(t.comments.clone()),
148 Default::default()
149 ),
150 issue_169,
151 r#"
152export class Foo {
153 func(a, b = Date.now()) {
154 return {a};
155 }
156}
157"#
158 );
159
160 test!(
161 ::swc_ecma_parser::Syntax::default(),
162 |t| es2015(
163 Mark::fresh(Mark::root()),
164 Some(t.comments.clone()),
165 Default::default()
166 ),
167 issue_189,
168 r#"
169class HomePage extends React.Component {}
170"#
171 );
172
173 test!(
174 ::swc_ecma_parser::Syntax::default(),
175 |t| es2015(
176 Mark::fresh(Mark::root()),
177 Some(t.comments.clone()),
178 Default::default()
179 ),
180 issue_227,
181 "export default function fn1(...args) {
182 fn2(...args);
183}"
184 );
185
186 test!(
187 ::swc_ecma_parser::Syntax::default(),
188 |_| (
189 block_scoped_functions(),
190 resolver(Mark::new(), Mark::new(), false)
191 ),
192 issue_271,
193 "
194function foo(scope) {
195 scope.startOperation = startOperation;
196
197 function startOperation(operation) {
198 scope.agentOperation = operation;
199 }
200}
201"
202 );
203
204 test!(
232 ::swc_ecma_parser::Syntax::default(),
233 |t| es2015(
234 Mark::fresh(Mark::root()),
235 Some(t.comments.clone()),
236 Default::default()
237 ),
238 issue_413,
239 r#"
240export const getBadgeBorderRadius = (text, color) => {
241 return (text && style) || {}
242}"#
243 );
244
245 test!(
246 ::swc_ecma_parser::Syntax::default(),
247 |t| es2015(
248 Mark::fresh(Mark::root()),
249 Some(t.comments.clone()),
250 Default::default()
251 ),
252 issue_400_1,
253 "class A {
254 constructor() {
255 this.a_num = 10;
256 }
257
258 print() {
259 expect(this.a_num).toBe(10);
260 }
261}
262
263class B extends A {
264 constructor(num) {
265 super();
266 this.b_num = num;
267 }
268
269 print() {
270 expect(this.b_num).toBe(20);
271 super.print();
272 }
273}
274"
275 );
276
277 test_exec!(
278 ::swc_ecma_parser::Syntax::default(),
279 |t| es2015(
280 Mark::fresh(Mark::root()),
281 Some(t.comments.clone()),
282 Default::default()
283 ),
284 issue_400_2,
285 "class A {
286 constructor() {
287 this.a_num = 10;
288 }
289
290 print() {
291 expect(this.a_num).toBe(10);
292 }
293}
294
295class B extends A {
296 constructor(num) {
297 super();
298 this.b_num = num;
299 }
300
301 print() {
302 expect(this.b_num).toBe(20);
303 super.print();
304 }
305}
306
307return new B(20).print()"
308 );
309
310 test!(
311 ::swc_ecma_parser::Syntax::default(),
312 |t| es2015(
313 Mark::fresh(Mark::root()),
314 Some(t.comments.clone()),
315 Default::default()
316 ),
317 issue_1660_1,
318 "
319 console.log(class {run(){}});
320 "
321 );
322
323 test_exec!(
324 ::swc_ecma_parser::Syntax::default(),
325 |t| es2015(
326 Mark::fresh(Mark::root()),
327 Some(t.comments.clone()),
328 Default::default()
329 ),
330 issue_2682,
331 "class MyObject extends null {
332 constructor() {
333 return Object.create(new.target.prototype);
334 }
335 }
336 var obj = new MyObject();
337 expect(obj.constructor).toBe(MyObject);
338 "
339 );
340
341 test!(
342 ::swc_ecma_parser::Syntax::default(),
343 |t| es2015(
344 Mark::fresh(Mark::root()),
345 Some(t.comments.clone()),
346 Config {
347 classes: classes::Config {
348 set_class_methods: true,
349 ..classes::Config::default()
350 },
351 ..Config::default()
352 }
353 ),
354 should_escape_keyword_in_method,
355 r#"
356export class Foo {
357 let() {}
358}
359"#
360 );
361
362 test!(
363 ::swc_ecma_parser::Syntax::default(),
364 |t| es2015(
365 Mark::fresh(Mark::root()),
366 Some(t.comments.clone()),
367 Config {
368 ..Default::default()
369 }
370 ),
371 issue_8871,
372 r#"
373 const x = "</" + "script>";
374 const y = "<\/script>";
375 const z = "\/\/ \\";
376 export { x, y, z };
377 "#
378 );
379}