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;
37mod 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 typeof_symbol(),
46 )
47}
48
49pub fn es2015<C>(unresolved_mark: Mark, comments: Option<C>, c: Config) -> impl Pass
59where
60 C: Comments + Clone,
61{
62 (
63 (
64 regexp(regexp::Config {
65 dot_all_regex: false,
66 has_indices: false,
67 lookbehind_assertion: false,
68 named_capturing_groups_regex: false,
69 sticky_regex: true,
70 unicode_property_regex: false,
71 unicode_regex: true,
72 unicode_sets_regex: false,
73 }),
74 block_scoped_functions(),
75 template_literal(c.template_literal),
76 classes(c.classes),
77 new_target(),
78 spread(c.spread),
79 ),
80 if !c.typescript {
82 Some(object_super())
83 } else {
84 None
85 },
86 shorthand(),
87 function_name(),
88 for_of(c.for_of),
89 parameters(c.parameters, unresolved_mark),
92 (
93 exprs(unresolved_mark),
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 spread: spread::Config,
119
120 #[serde(default)]
121 pub regenerator: regenerator::Config,
122
123 #[serde(default)]
124 pub template_literal: template_literal::Config,
125
126 #[serde(default)]
127 pub parameters: parameters::Config,
128
129 #[serde(default)]
130 pub typescript: bool,
131}
132
133#[cfg(test)]
134mod tests {
135 use swc_ecma_transforms_base::resolver;
136 use swc_ecma_transforms_testing::{test, test_exec};
137
138 use super::*;
139
140 test!(
141 ::swc_ecma_parser::Syntax::default(),
142 |t| es2015(
143 Mark::fresh(Mark::root()),
144 Some(t.comments.clone()),
145 Default::default()
146 ),
147 issue_169,
148 r#"
149export class Foo {
150 func(a, b = Date.now()) {
151 return {a};
152 }
153}
154"#
155 );
156
157 test!(
158 ::swc_ecma_parser::Syntax::default(),
159 |t| es2015(
160 Mark::fresh(Mark::root()),
161 Some(t.comments.clone()),
162 Default::default()
163 ),
164 issue_189,
165 r#"
166class HomePage extends React.Component {}
167"#
168 );
169
170 test!(
171 ::swc_ecma_parser::Syntax::default(),
172 |t| es2015(
173 Mark::fresh(Mark::root()),
174 Some(t.comments.clone()),
175 Default::default()
176 ),
177 issue_227,
178 "export default function fn1(...args) {
179 fn2(...args);
180}"
181 );
182
183 test!(
184 ::swc_ecma_parser::Syntax::default(),
185 |_| (
186 block_scoped_functions(),
187 resolver(Mark::new(), Mark::new(), false)
188 ),
189 issue_271,
190 "
191function foo(scope) {
192 scope.startOperation = startOperation;
193
194 function startOperation(operation) {
195 scope.agentOperation = operation;
196 }
197}
198"
199 );
200
201 test!(
229 ::swc_ecma_parser::Syntax::default(),
230 |t| es2015(
231 Mark::fresh(Mark::root()),
232 Some(t.comments.clone()),
233 Default::default()
234 ),
235 issue_413,
236 r#"
237export const getBadgeBorderRadius = (text, color) => {
238 return (text && style) || {}
239}"#
240 );
241
242 test!(
243 ::swc_ecma_parser::Syntax::default(),
244 |t| es2015(
245 Mark::fresh(Mark::root()),
246 Some(t.comments.clone()),
247 Default::default()
248 ),
249 issue_400_1,
250 "class A {
251 constructor() {
252 this.a_num = 10;
253 }
254
255 print() {
256 expect(this.a_num).toBe(10);
257 }
258}
259
260class B extends A {
261 constructor(num) {
262 super();
263 this.b_num = num;
264 }
265
266 print() {
267 expect(this.b_num).toBe(20);
268 super.print();
269 }
270}
271"
272 );
273
274 test_exec!(
275 ::swc_ecma_parser::Syntax::default(),
276 |t| es2015(
277 Mark::fresh(Mark::root()),
278 Some(t.comments.clone()),
279 Default::default()
280 ),
281 issue_400_2,
282 "class A {
283 constructor() {
284 this.a_num = 10;
285 }
286
287 print() {
288 expect(this.a_num).toBe(10);
289 }
290}
291
292class B extends A {
293 constructor(num) {
294 super();
295 this.b_num = num;
296 }
297
298 print() {
299 expect(this.b_num).toBe(20);
300 super.print();
301 }
302}
303
304return new B(20).print()"
305 );
306
307 test!(
308 ::swc_ecma_parser::Syntax::default(),
309 |t| es2015(
310 Mark::fresh(Mark::root()),
311 Some(t.comments.clone()),
312 Default::default()
313 ),
314 issue_1660_1,
315 "
316 console.log(class {run(){}});
317 "
318 );
319
320 test_exec!(
321 ::swc_ecma_parser::Syntax::default(),
322 |t| es2015(
323 Mark::fresh(Mark::root()),
324 Some(t.comments.clone()),
325 Default::default()
326 ),
327 issue_2682,
328 "class MyObject extends null {
329 constructor() {
330 return Object.create(new.target.prototype);
331 }
332 }
333 var obj = new MyObject();
334 expect(obj.constructor).toBe(MyObject);
335 "
336 );
337
338 test!(
339 ::swc_ecma_parser::Syntax::default(),
340 |t| es2015(
341 Mark::fresh(Mark::root()),
342 Some(t.comments.clone()),
343 Config {
344 classes: classes::Config {
345 set_class_methods: true,
346 ..classes::Config::default()
347 },
348 ..Config::default()
349 }
350 ),
351 should_escape_keyword_in_method,
352 r#"
353export class Foo {
354 let() {}
355}
356"#
357 );
358
359 test!(
360 ::swc_ecma_parser::Syntax::default(),
361 |t| es2015(
362 Mark::fresh(Mark::root()),
363 Some(t.comments.clone()),
364 Config {
365 ..Default::default()
366 }
367 ),
368 issue_8871,
369 r#"
370 const x = "</" + "script>";
371 const y = "<\/script>";
372 const z = "\/\/ \\";
373 export { x, y, z };
374 "#
375 );
376}