mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 04:47:03 +03:00
fix(swc): Fix bugs (#2067)
swc_ecma_transforms_compat: - Fix optional chaining. (#2063) node/swc: - Fix definition of `ImportDeclaration`. (#2059) testing: - Allow using `testing` with stable `rustc`. testing_macros: - Add `#[inline(never)]`.
This commit is contained in:
parent
883c1ac4e4
commit
1b9584cfc0
9
Cargo.lock
generated
9
Cargo.lock
generated
@ -2488,7 +2488,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_transforms_compat"
|
||||
version = "0.29.2"
|
||||
version = "0.29.3"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"fxhash",
|
||||
@ -2622,9 +2622,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_transforms_testing"
|
||||
version = "0.26.1"
|
||||
version = "0.26.2"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"anyhow",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"swc_common",
|
||||
@ -2818,7 +2819,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "testing"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"difference",
|
||||
@ -2833,7 +2834,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "testing_macros"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"glob",
|
||||
|
@ -73,7 +73,7 @@ pub struct ImportDecl {
|
||||
#[serde(rename = "source")]
|
||||
pub src: Str,
|
||||
|
||||
#[serde(rename = "typeOnly")]
|
||||
#[serde(default, rename = "typeOnly")]
|
||||
pub type_only: bool,
|
||||
|
||||
#[serde(default)]
|
||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecma_transforms_compat"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.29.2"
|
||||
version = "0.29.3"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
@ -454,39 +454,71 @@ impl OptChaining {
|
||||
},
|
||||
"_obj",
|
||||
);
|
||||
let obj = if !is_super_access && aliased {
|
||||
self.vars_with_init.push(VarDeclarator {
|
||||
span: obj_span,
|
||||
definite: false,
|
||||
name: Pat::Ident(this_obj.clone().into()),
|
||||
init: Some(obj),
|
||||
});
|
||||
|
||||
Box::new(Expr::Ident(this_obj.clone()))
|
||||
} else {
|
||||
obj
|
||||
};
|
||||
let i = private_ident!(obj_span, "ref");
|
||||
let obj_expr = if !is_super_access && aliased {
|
||||
self.vars_without_init.push(VarDeclarator {
|
||||
span: obj_span,
|
||||
definite: false,
|
||||
name: Pat::Ident(i.clone().into()),
|
||||
name: Pat::Ident(this_obj.clone().into()),
|
||||
init: None,
|
||||
});
|
||||
|
||||
match *obj {
|
||||
Expr::Member(
|
||||
obj
|
||||
@
|
||||
MemberExpr {
|
||||
obj: ExprOrSuper::Expr(..),
|
||||
..
|
||||
},
|
||||
) => Box::new(Expr::Member(MemberExpr {
|
||||
span: obj.span,
|
||||
obj: Expr::Assign(AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
op: op!("="),
|
||||
left: PatOrExpr::Pat(Box::new(Pat::Ident(
|
||||
this_obj.clone().into(),
|
||||
))),
|
||||
right: obj.obj.expect_expr(),
|
||||
})
|
||||
.as_obj(),
|
||||
prop: obj.prop,
|
||||
computed: obj.computed,
|
||||
})),
|
||||
_ => Box::new(Expr::Assign(AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
op: op!("="),
|
||||
left: PatOrExpr::Pat(Box::new(Pat::Ident(
|
||||
this_obj.clone().into(),
|
||||
))),
|
||||
right: obj,
|
||||
})),
|
||||
}
|
||||
} else {
|
||||
obj
|
||||
};
|
||||
|
||||
let tmp = private_ident!(obj_span, "ref");
|
||||
|
||||
self.vars_without_init.push(VarDeclarator {
|
||||
span: obj_span,
|
||||
definite: false,
|
||||
name: Pat::Ident(tmp.clone().into()),
|
||||
init: None,
|
||||
});
|
||||
|
||||
(
|
||||
Box::new(Expr::Assign(AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
left: PatOrExpr::Pat(Box::new(Pat::Ident(i.clone().into()))),
|
||||
left: PatOrExpr::Pat(Box::new(Pat::Ident(tmp.clone().into()))),
|
||||
op: op!("="),
|
||||
right: obj,
|
||||
right: obj_expr,
|
||||
})),
|
||||
Box::new(Expr::Ident(i.clone())),
|
||||
Box::new(Expr::Ident(tmp.clone())),
|
||||
Box::new(Expr::Call(CallExpr {
|
||||
span,
|
||||
callee: ExprOrSuper::Expr(Box::new(Expr::Member(MemberExpr {
|
||||
span: DUMMY_SP,
|
||||
obj: ExprOrSuper::Expr(Box::new(Expr::Ident(i.clone()))),
|
||||
obj: ExprOrSuper::Expr(Box::new(Expr::Ident(tmp.clone()))),
|
||||
prop: Box::new(Expr::Ident(Ident::new("call".into(), span))),
|
||||
computed: false,
|
||||
}))),
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::{fs::read_to_string, path::PathBuf};
|
||||
use swc_ecma_parser::{Syntax, TsConfig};
|
||||
use swc_ecma_transforms_compat::es2020::optional_chaining;
|
||||
use swc_ecma_transforms_testing::{test, test_exec};
|
||||
use swc_ecma_transforms_testing::{compare_stdout, test, test_exec};
|
||||
use swc_ecma_visit::Fold;
|
||||
|
||||
fn tr(_: ()) -> impl Fold {
|
||||
@ -298,7 +299,7 @@ foo?.bar()?.()
|
||||
|
||||
"#,
|
||||
r#"
|
||||
var ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9;
|
||||
var ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, _obj, ref9;
|
||||
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(foo, foo.bar, false);
|
||||
@ -309,8 +310,7 @@ foo === null || foo === void 0 ? void 0 : (ref2 = foo()) === null || ref2 === vo
|
||||
(ref4 = foo.bar) === null || ref4 === void 0 ? void 0 : (ref5 = ref4.call(foo)) === 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(foo).baz;
|
||||
foo === null || foo === void 0 ? void 0 : (ref7 = foo.bar) === null || ref7 === void 0 ? void 0 : (ref8 = ref7.call(foo)) === null || ref8 === void 0 ? void 0 : ref8.baz;
|
||||
var _obj = foo === null || foo === void 0 ? void 0 : foo.bar();
|
||||
(ref9 = _obj) === null || ref9 === void 0 ? void 0 : ref9.call(_obj);"#
|
||||
(ref9 = _obj = foo === null || foo === void 0 ? void 0 : foo.bar()) === null || ref9 === void 0 ? void 0 : ref9.call(_obj);"#
|
||||
);
|
||||
|
||||
// general_unary_exec
|
||||
@ -696,11 +696,11 @@ test!(
|
||||
const patch = PATCHES.get(ident)?.();
|
||||
",
|
||||
"
|
||||
var ref;
|
||||
var _obj, ref;
|
||||
const PATCHES = new Map();
|
||||
const ident = \"foo\";
|
||||
var _obj = PATCHES.get(ident);
|
||||
const patch = (ref = _obj) === null || ref === void 0 ? void 0 : ref.call(_obj);
|
||||
const patch = (ref = _obj = PATCHES.get(ident)) === null || ref === void 0 ? void 0 : \
|
||||
ref.call(_obj);
|
||||
"
|
||||
);
|
||||
|
||||
@ -718,11 +718,18 @@ test!(
|
||||
"
|
||||
function bug() {
|
||||
const arrowFn = (arg)=>{
|
||||
var ref;
|
||||
var _object = this.object[arg];
|
||||
return (ref = _object) === null || ref === void 0 ? void 0 : ref.call(_object);
|
||||
var _object, ref;
|
||||
return (ref = (_object = this.object)[arg]) === null || ref === void 0 ? void 0 : \
|
||||
ref.call(_object);
|
||||
};
|
||||
}
|
||||
bug();
|
||||
"
|
||||
);
|
||||
|
||||
#[testing::fixture("tests/fixture/opt-chain/**/exec.js")]
|
||||
fn exec(input: PathBuf) {
|
||||
let src = read_to_string(&input).unwrap();
|
||||
|
||||
compare_stdout(Default::default(), |_| optional_chaining(), &src);
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
const myVar = {
|
||||
target: {
|
||||
value: "ABC"
|
||||
}
|
||||
}
|
||||
|
||||
console.log(myVar.target.value.toLowerCase?.())
|
@ -0,0 +1,5 @@
|
||||
const myVar = {
|
||||
value: "ABC"
|
||||
}
|
||||
|
||||
console.log(myVar.value.toLowerCase?.())
|
@ -6,12 +6,13 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecma_transforms_testing"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.26.1"
|
||||
version = "0.26.2"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
ansi_term = "0.12.1"
|
||||
anyhow = "1"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
swc_common = {version = "0.11.0", path = "../../../common"}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use ansi_term::Color;
|
||||
use anyhow::{bail, Context, Error};
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::{
|
||||
env,
|
||||
@ -16,7 +17,7 @@ use swc_common::{
|
||||
};
|
||||
use swc_ecma_ast::{Pat, *};
|
||||
use swc_ecma_codegen::Emitter;
|
||||
use swc_ecma_parser::{error::Error, lexer::Lexer, Parser, StringInput, Syntax};
|
||||
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax};
|
||||
use swc_ecma_transforms_base::{
|
||||
fixer,
|
||||
helpers::{inject_helpers, HELPERS},
|
||||
@ -93,7 +94,7 @@ impl<'a> Tester<'a> {
|
||||
op: F,
|
||||
) -> Result<T, ()>
|
||||
where
|
||||
F: FnOnce(&mut Parser<Lexer<StringInput>>) -> Result<T, Error>,
|
||||
F: FnOnce(&mut Parser<Lexer<StringInput>>) -> Result<T, swc_ecma_parser::error::Error>,
|
||||
{
|
||||
let fm = self
|
||||
.cm
|
||||
@ -234,7 +235,7 @@ impl VisitMut for RegeneratorHandler {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_tr<F, P>(_: &'static str, op: F, tester: &mut Tester<'_>) -> impl Fold
|
||||
fn make_tr<F, P>(op: F, tester: &mut Tester<'_>) -> impl Fold
|
||||
where
|
||||
F: FnOnce(&mut Tester<'_>) -> P,
|
||||
P: Fold,
|
||||
@ -266,7 +267,7 @@ pub fn test_transform<F, P>(
|
||||
|
||||
println!("----- Actual -----");
|
||||
|
||||
let tr = make_tr("actual", tr, tester);
|
||||
let tr = make_tr(tr, tester);
|
||||
let actual = tester.apply_transform(tr, "input.js", syntax, input)?;
|
||||
|
||||
match ::std::env::var("PRINT_HYGIENE") {
|
||||
@ -348,13 +349,49 @@ macro_rules! test {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn exec_tr<F, P>(test_name: &'static str, syntax: Syntax, tr: F, input: &str)
|
||||
/// Execute `node` for `input` and ensure that it prints same output after
|
||||
/// transformation.
|
||||
pub fn compare_stdout<F, P>(syntax: Syntax, tr: F, input: &str)
|
||||
where
|
||||
F: FnOnce(&mut Tester<'_>) -> P,
|
||||
P: Fold,
|
||||
{
|
||||
Tester::run(|tester| {
|
||||
let tr = make_tr(test_name, tr, tester);
|
||||
let tr = make_tr(tr, tester);
|
||||
|
||||
let module = tester.apply_transform(tr, "input.js", syntax, input)?;
|
||||
|
||||
let mut module = module
|
||||
.fold_with(&mut hygiene::hygiene())
|
||||
.fold_with(&mut fixer::fixer(Some(&tester.comments)));
|
||||
|
||||
let src_without_helpers = tester.print(&module, &tester.comments.clone());
|
||||
module = module.fold_with(&mut inject_helpers());
|
||||
|
||||
let transfomred_src = tester.print(&module, &tester.comments.clone());
|
||||
|
||||
println!(
|
||||
"\t>>>>> Orig <<<<<\n{}\n\t>>>>> Code <<<<<\n{}",
|
||||
input, src_without_helpers
|
||||
);
|
||||
|
||||
let expected = stdout_of(&input).unwrap();
|
||||
let actual = stdout_of(&transfomred_src).unwrap();
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Execute `jest` after transpiling `input` using `tr`.
|
||||
pub fn exec_tr<F, P>(test_name: &str, syntax: Syntax, tr: F, input: &str)
|
||||
where
|
||||
F: FnOnce(&mut Tester<'_>) -> P,
|
||||
P: Fold,
|
||||
{
|
||||
Tester::run(|tester| {
|
||||
let tr = make_tr(tr, tester);
|
||||
|
||||
let module = tester.apply_transform(
|
||||
tr,
|
||||
@ -442,6 +479,24 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn stdout_of(code: &str) -> Result<String, Error> {
|
||||
let actual_output = Command::new("node")
|
||||
.arg("-e")
|
||||
.arg(&code)
|
||||
.output()
|
||||
.context("failed to execute output of minifier")?;
|
||||
|
||||
if !actual_output.status.success() {
|
||||
bail!(
|
||||
"failed to execute:\n{}\n{}",
|
||||
String::from_utf8_lossy(&actual_output.stdout),
|
||||
String::from_utf8_lossy(&actual_output.stderr)
|
||||
)
|
||||
}
|
||||
|
||||
Ok(String::from_utf8_lossy(&actual_output.stdout).to_string())
|
||||
}
|
||||
|
||||
/// Test transformation.
|
||||
#[macro_export]
|
||||
macro_rules! test_exec {
|
||||
|
@ -1449,6 +1449,8 @@ export interface ExportDeclaration extends Node, HasSpan {
|
||||
export interface ImportDeclaration extends Node, HasSpan {
|
||||
type: "ImportDeclaration";
|
||||
|
||||
typeOnly?: boolean;
|
||||
|
||||
specifiers: ImportSpecifier[];
|
||||
|
||||
source: StringLiteral;
|
||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "testing"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
|
||||
[dependencies]
|
||||
ansi_term = "0.12.1"
|
||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "testing_macros"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
@ -159,6 +159,7 @@ pub fn expand(callee: &Ident, attr: Config) -> Result<Vec<ItemFn>, Error> {
|
||||
},
|
||||
{
|
||||
#[test]
|
||||
#[inline(never)]
|
||||
#[ignore]
|
||||
fn test_ident() {
|
||||
callee(::std::path::PathBuf::from(path_str));
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(test)]
|
||||
|
||||
pub use self::output::{NormalizedOutput, StdErr, StdOut, TestOutput};
|
||||
use difference::Changeset;
|
||||
use once_cell::sync::Lazy;
|
||||
|
7
tests/fixture/issue-2063/input/index.js
Normal file
7
tests/fixture/issue-2063/input/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
const myVar = {
|
||||
target: {
|
||||
value: "ABC"
|
||||
}
|
||||
}
|
||||
|
||||
console.log(myVar.target.value.toLowerCase?.());
|
7
tests/fixture/issue-2063/output/index.js
Normal file
7
tests/fixture/issue-2063/output/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
var _value, ref;
|
||||
var myVar = {
|
||||
target: {
|
||||
value: "ABC"
|
||||
}
|
||||
};
|
||||
console.log((ref = (_value = myVar.target.value).toLowerCase) === null || ref === void 0 ? void 0 : ref.call(_value));
|
Loading…
Reference in New Issue
Block a user