swc/ecmascript/transforms/tests/proposal_optional_chaining.rs
강동윤 706ae00523
Fix deeply nested optional chaining (#735)
- Handle deeply nested optional chaining expression correctly (Closes #732)
2020-03-28 11:59:45 +09:00

574 lines
11 KiB
Rust

#![feature(box_syntax)]
#![feature(test)]
#![feature(box_patterns)]
#![feature(specialization)]
use swc_ecma_parser::{Syntax, TsConfig};
use swc_ecma_transforms::{pass::Pass, proposals::optional_chaining};
#[macro_use]
mod common;
fn tr(_: ()) -> impl Pass {
optional_chaining()
}
fn syntax() -> Syntax {
Syntax::Typescript(TsConfig {
..Default::default()
})
}
// general_memoize_loose
// general_lhs_assignment_read_and_update
// general_function_call_loose
// regression_7642
// general_super_method_call_loose
// general_lhs_update
// general_assignment
test!(
syntax(),
|_| tr(()),
general_assignment,
r#"
"use strict";
const obj = {
a: {
b: {
c: {
d: 2,
},
},
},
};
const a = obj?.a;
const b = obj?.a?.b;
const bad = obj?.b?.b;
let val;
val = obj?.a?.b;
"#,
r#"
"use strict";
var ref, ref1, ref2;
const obj = {
a: {
b: {
c: {
d: 2
}
}
}
};
const a = obj === null || obj === void 0 ? void 0 : obj.a;
const b = obj === null || obj === void 0 ? void 0 : (ref = obj.a) === null || ref === void 0 ? void 0 : ref.b;
const bad = obj === null || obj === void 0 ? void 0 : (ref1 = obj.b) === null || ref1 === void 0 ? void 0 : ref1.b;
let val;
val = obj === null || obj === void 0 ? void 0 : (ref2 = obj.a) === null || ref2 === void 0 ? void 0 : ref2.b;
"#
);
// general_memoize
test!(
syntax(),
|_| tr(()),
general_memoize,
r#"
function test(foo) {
foo?.bar;
foo?.bar?.baz;
foo?.(foo);
foo?.bar()
foo.bar?.(foo.bar, false)
foo?.bar?.(foo.bar, true)
foo.bar?.baz(foo.bar, false)
foo?.bar?.baz(foo.bar, true)
foo.bar?.baz?.(foo.bar, false)
foo?.bar?.baz?.(foo.bar, true)
}
"#,
r#"
function test(foo) {
var ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8;
foo === null || foo === void 0 ? void 0 : foo.bar;
foo === null || foo === void 0 ? void 0 : (ref = foo.bar) === null || ref === void 0 ? void 0 : ref.baz;
foo === null || foo === void 0 ? void 0 : foo(foo);
foo === null || foo === void 0 ? void 0 : foo.bar();
(ref1 = foo.bar) === null || ref1 === void 0 ? void 0 : ref1.call(ref1, foo.bar, false);
foo === null || foo === void 0 ? void 0 : (ref2 = foo.bar) === null || ref2 === void 0 ? void 0 : ref2.call(ref2, foo.bar, true);
(ref3 = foo.bar) === null || ref3 === void 0 ? void 0 : ref3.baz(foo.bar, false);
foo === null || foo === void 0 ? void 0 : (ref4 = foo.bar) === null || ref4 === void 0 ? void 0 : ref4.baz(foo.bar, true);
(ref5 = foo.bar) === null || ref5 === void 0 ? void 0 : (ref6 = ref5.baz) === null || ref6 === void 0 ? void 0 : ref6.call(ref6, foo.bar, false);
foo === null || foo === void 0 ? void 0 : (ref7 = foo.bar) === null || ref7 === void 0 ? void 0 : (ref8 = ref7.baz) === null || ref8 === void 0 ? void 0 : ref8.call(ref8, foo.bar, true);
}
"#
);
// general_containers
test!(
syntax(),
|_| tr(()),
general_containers,
r#"
var street = user.address?.street
street = user.address?.street
test(a?.b, 1);
(a?.b, 2);
"#,
r#"
var ref, ref1;
var street = (ref = user.address) === null || ref === void 0 ? void 0 : ref.street;
street = (ref1 = user.address) === null || ref1 === void 0 ? void 0 : ref1.street;
test(a === null || a === void 0 ? void 0 : a.b, 1);
a === null || a === void 0 ? void 0 : a.b, 2;
"#
);
// general_function_call_spread
// general_lhs_assignment
// general_delete_exec
test_exec!(
syntax(),
|_| tr(()),
general_delete_exec,
r#"
"use strict";
const obj = {
a: {
b: 0,
},
};
let test = delete obj?.a?.b;
expect(obj.a.b).toBeUndefined();
expect(test).toBe(true);
test = delete obj?.a.b;
expect(obj.a.b).toBeUndefined();
expect(test).toBe(true);
test = delete obj?.b?.b;
expect(obj.b).toBeUndefined();
expect(test).toBeUndefined();
delete obj?.a;
expect(obj.a).toBeUndefined();
"#
);
// general_member_access
test!(
syntax(),
|_| tr(()),
general_member_access,
r#"
foo?.bar;
a?.b.c?.d.e;
a.b?.c.d?.e;
a.b.c?.d?.e;
orders?.[0].price;
orders?.[0]?.price;
orders[client?.key].price;
orders[client.key]?.price;
(0, a?.b).c;
(0, (0, a?.b).c?.d).e;
"#,
r#"
var ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7;
foo === null || foo === void 0 ? void 0 : foo.bar;
(ref = a === null || a === void 0 ? void 0 : a.b.c) === null || ref === void 0 ? void 0 : ref.d.e;
(ref1 = (ref2 = a.b) === null || ref2 === void 0 ? void 0 : ref2.c.d) === null || ref1 === void 0 ? void 0 : ref1.e;
(ref3 = a.b.c) === null || ref3 === void 0 ? void 0 : (ref4 = ref3.d) === null || ref4 === void 0 ? void 0 : ref4.e;
orders === null || orders === void 0 ? void 0 : orders[0].price;
orders === null || orders === void 0 ? void 0 : (ref5 = orders[0]) === null || ref5 === void 0 ? void 0 : ref5.price;
orders[client === null || client === void 0 ? void 0 : client.key].price;
(ref6 = orders[client.key]) === null || ref6 === void 0 ? void 0 : ref6.price;
(a === null || a === void 0 ? void 0 : a.b).c;
((ref7 = (a === null || a === void 0 ? void 0 : a.b).c) === null || ref7 === void 0 ? void 0 : ref7.d).e;
"#
);
// general_unary
test!(
syntax(),
|_| tr(()),
general_unary,
r#"
"use strict";
const obj = {
a: {
b: 0,
},
};
let test = +obj?.a?.b;
test = +obj?.a.b;
test = +obj?.b?.b;
test = +obj?.b?.b;
"#,
r#"
"use strict";
var ref, ref1, ref2;
const obj = {
a: {
b: 0
}
};
let test = +(obj === null || obj === void 0 ? void 0 : (ref = obj.a) === null || ref === void 0 ? void 0 : ref.b);
test = +(obj === null || obj === void 0 ? void 0 : obj.a.b);
test = +(obj === null || obj === void 0 ? void 0 : (ref1 = obj.b) === null || ref1 === void 0 ? void 0 : ref1.b);
test = +(obj === null || obj === void 0 ? void 0 : (ref2 = obj.b) === null || ref2 === void 0 ? void 0 : ref2.b);
"#
);
// regression_8354
// general_function_call
test!(
syntax(),
|_| tr(()),
general_function_call,
r#"
foo?.(foo);
foo?.bar()
foo.bar?.(foo.bar, false)
foo?.bar?.(foo.bar, true)
foo?.().bar
foo?.()?.bar
foo.bar?.().baz
foo.bar?.()?.baz
foo?.bar?.().baz
foo?.bar?.()?.baz
"#,
r#"
var ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8;
foo === null || foo === void 0 ? void 0 : foo(foo);
foo === null || foo === void 0 ? void 0 : foo.bar();
(ref = foo.bar) === null || ref === void 0 ? void 0 : ref.call(ref, foo.bar, false);
foo === null || foo === void 0 ? void 0 : (ref1 = foo.bar) === null || ref1 === void 0 ? void 0 : ref1.call(ref1, foo.bar, true);
foo === null || foo === void 0 ? void 0 : foo().bar;
foo === null || foo === void 0 ? void 0 : (ref2 = foo()) === null || ref2 === void 0 ? void 0 : ref2.bar;
(ref3 = foo.bar) === null || ref3 === void 0 ? void 0 : ref3.call(ref3).baz;
(ref4 = foo.bar) === null || ref4 === void 0 ? void 0 : (ref5 = ref4.call(ref4)) === null || ref5 === void 0 ? void 0 : ref5.baz;
foo === null || foo === void 0 ? void 0 : (ref6 = foo.bar) === null || ref6 === void 0 ? void 0 : ref6.call(ref6).baz;
foo === null || foo === void 0 ? void 0 : (ref7 = foo.bar) === null || ref7 === void 0 ? void 0 : (ref8 = ref7.call(ref7)) === null || ref8 === void 0 ? void 0 : ref8.baz;
"#
);
// general_unary_exec
test_exec!(
syntax(),
|_| tr(()),
general_unary_exec,
r#"
"use strict";
const obj = {
a: {
b: 0,
},
};
let test = +obj?.a?.b;
expect(test).toBe(0);
test = +obj?.a.b;
expect(test).toBe(0);
test = +obj?.b?.b;
expect(test).toBe(NaN);
test = +obj?.b?.b;
expect(test).toBe(NaN);
"#
);
// general_call_exec
test_exec!(
syntax(),
|_| tr(()),
general_call_exec,
r#"
"#
);
// general_delete
test!(
syntax(),
|_| tr(()),
general_delete,
r#"
"use strict";
const obj = {
a: {
b: 0,
},
};
let test = delete obj?.a?.b;
test = delete obj?.a.b;
test = delete obj?.b?.b;
delete obj?.a;
"#,
r#"
"use strict";
var ref, ref1;
const obj = {
a: {
b: 0
}
};
let test = obj === null || obj === void 0 ? void 0 : (ref = obj.a) === null || ref === void 0 ? void 0 : delete ref.b;
test = obj === null || obj === void 0 ? void 0 : delete obj.a.b;
test = obj === null || obj === void 0 ? void 0 : (ref1 = obj.b) === null || ref1 === void 0 ? void 0 : delete ref1.b;
obj === null || obj === void 0 ? void 0 : delete obj.a;
"#
);
// regression_8354_exec
test_exec!(
syntax(),
|_| tr(()),
regression_8354_exec,
r#"
const foo = undefined;
const bar = 'bar';
const foobar = foo?.replace(`foo${bar}`, '');
expect(foobar).toBe(undefined);
"#
);
// general_assignment_exec
test_exec!(
syntax(),
|_| tr(()),
general_assignment_exec,
r#"
"use strict";
const obj = {
a: {
b: {
c: {
d: 2,
},
},
},
};
const a = obj?.a;
expect(a).toBe(obj.a);
const b = obj?.a?.b;
expect(b).toBe(obj.a.b);
const bad = obj?.b?.b;
expect(bad).toBeUndefined();
let val;
val = obj?.a?.b;
expect(val).toBe(obj.a.b);
expect(() => {
const bad = obj?.b.b;
}).toThrow();
"#
);
// general_super_method_call
test!(
syntax(),
|_| tr(()),
general_super_method_call,
r#"
"use strict";
class Base {
method() {
return 'Hello!';
}
}
class Derived extends Base {
method() {
return super.method?.()
}
}
"#,
r#"
"use strict";
class Base {
method() {
return 'Hello!';
}
}
class Derived extends Base {
method() {
var ref;
return (ref = super.method) === null || ref === void 0 ? void 0 : ref.call(this);
}
}
"#
);
test!(
syntax(),
|_| tr(()),
simple_1,
"obj?.a",
"obj === null || obj === void 0 ? void 0 : obj.a;"
);
test!(
syntax(),
|_| tr(()),
simple_2,
"obj?.a?.b",
"var ref;
obj === null || obj === void 0 ? void 0 : (ref = obj.a) === null || ref === void 0 ? void 0 : \
ref.b;"
);
test!(
syntax(),
|_| tr(()),
simple_3,
"obj?.a?.b.c",
"var ref;
obj === null || obj === void 0 ? void 0 : (ref = obj.a) === null || ref === void 0 ? void 0 : \
ref.b.c;"
);
test!(
syntax(),
|_| tr(()),
call_1,
"obj?.a?.b()",
"var ref;
obj === null || obj === void 0 ? void 0 : (ref = obj.a) === null || ref === void 0 ? void 0 : \
ref.b();",
ok_if_code_eq
);
test!(
syntax(),
|_| tr(()),
call_2,
"a?.b?.c?.()",
"var ref, ref1;
a === null || a === void 0
? void 0
: (ref = a.b) === null || ref === void 0
? void 0
: (ref1 = ref.c) === null || ref1 === void 0
? void 0
: ref1.call(ref1);"
);
test!(
syntax(),
|_| tr(()),
issue_732_1,
"test.a?.b.c.d",
"var ref;
(ref = test.a) === null || ref === void 0 ? void 0 : ref.b.c.d"
);
test!(
syntax(),
|_| tr(()),
issue_732_2,
"test.a?.b.c",
"var ref;
(ref = test.a) === null || ref === void 0 ? void 0 : ref.b.c;"
);
test!(
syntax(),
|_| tr(()),
issue_732_3,
"test.a?.b.c.d.e.f.g.h.i",
"var ref;
(ref = test.a) === null || ref === void 0 ? void 0 : ref.b.c.d.e.f.g.h.i"
);