mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 21:54:36 +03:00
Fix bugs (#339)
swc_ecma_parser: - fix parsing of type query (#338) - fix parsing of `in` in a let / const declaration (#337) swc_ecma_transforms: - string literal is computed (#336) - modules: handle imports in lhs of assignment correctly (#335)
This commit is contained in:
parent
2025f20e8c
commit
13bf89d08c
@ -366,3 +366,17 @@ fn issue_328() {
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_337() {
|
||||
test_parser(
|
||||
"const foo = 'bar' in bas ? 'beep' : 'boop';",
|
||||
Default::default(),
|
||||
|p| {
|
||||
p.parse_module().map_err(|mut e| {
|
||||
e.emit();
|
||||
()
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -438,7 +438,7 @@ impl<'a, I: Input> Parser<'a, I> {
|
||||
tok!("var") => VarDeclKind::Var,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let should_include_in = kind == VarDeclKind::Var;
|
||||
let should_include_in = kind != VarDeclKind::Var;
|
||||
|
||||
let mut decls = vec![];
|
||||
let mut first = true;
|
||||
|
@ -159,7 +159,11 @@ impl<'a, I: Input> Parser<'a, I> {
|
||||
let mut entity = TsEntityName::Ident(self.parse_ident_name()?);
|
||||
while eat!('.') {
|
||||
let left = entity;
|
||||
let right = self.parse_ident(allow_reserved_words, allow_reserved_words)?;
|
||||
let right = if allow_reserved_words {
|
||||
self.parse_ident_name()?
|
||||
} else {
|
||||
self.parse_ident(false, false)?
|
||||
};
|
||||
entity = TsEntityName::TsQualifiedName(Box::new(TsQualifiedName { left, right }));
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unexpected initializer in for in/of loop
|
||||
--> $DIR/tests/test262-parser/fail/0ddab4a1a651034c.js:1:6
|
||||
error: Expected Semi, got Some(RParen)
|
||||
--> $DIR/tests/test262-parser/fail/0ddab4a1a651034c.js:1:24
|
||||
|
|
||||
1 | for (let x = 42 in list) process(x);
|
||||
| ^^^^^^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unexpected initializer in for in/of loop
|
||||
--> $DIR/tests/test262-parser/fail/154f02d86fce5e81.js:1:6
|
||||
error: Expected Semi, got Some(RParen)
|
||||
--> $DIR/tests/test262-parser/fail/154f02d86fce5e81.js:1:22
|
||||
|
|
||||
1 | for (const x = 0 in y){}
|
||||
| ^^^^^^^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unexpected initializer in for in/of loop
|
||||
--> $DIR/tests/test262-parser/fail/3162394f5bc07198.js:1:5
|
||||
error: Expected Semi, got Some(RParen)
|
||||
--> $DIR/tests/test262-parser/fail/3162394f5bc07198.js:1:21
|
||||
|
|
||||
1 | for(const a = 0 in b);
|
||||
| ^^^^^^^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unexpected initializer in for in/of loop
|
||||
--> $DIR/tests/test262-parser/fail/33d43e9f01bda5ce.js:1:6
|
||||
error: Expected Semi, got Some(RParen)
|
||||
--> $DIR/tests/test262-parser/fail/33d43e9f01bda5ce.js:1:20
|
||||
|
|
||||
1 | for (let x = 0 in y){}
|
||||
| ^^^^^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unexpected initializer in for in/of loop
|
||||
--> $DIR/tests/test262-parser/fail/c75e9f5ea55611f3.js:1:5
|
||||
error: Expected Semi, got Some(RParen)
|
||||
--> $DIR/tests/test262-parser/fail/c75e9f5ea55611f3.js:1:23
|
||||
|
|
||||
1 | for(let x=1 in [1,2,3]) 0
|
||||
| ^^^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unexpected initializer in for in/of loop
|
||||
--> $DIR/tests/test262-parser/fail/e01265e2211e48b3.js:1:5
|
||||
error: Expected Semi, got Some(RParen)
|
||||
--> $DIR/tests/test262-parser/fail/e01265e2211e48b3.js:1:19
|
||||
|
|
||||
1 | for(let a = 0 in b);
|
||||
| ^^^^^^^^^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Expected Semi, got Some(RParen)
|
||||
--> $DIR/tests/test262-parser/fail/e3fbcf63d7e43ead.js:1:23
|
||||
error: Unexpected initializer in for in/of loop
|
||||
--> $DIR/tests/test262-parser/fail/e3fbcf63d7e43ead.js:1:5
|
||||
|
|
||||
1 | for(var x=1 in [1,2,3]) 0
|
||||
| ^
|
||||
| ^^^^^^^
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
const bar = bas as typeof beep.delete
|
@ -0,0 +1,90 @@
|
||||
{
|
||||
"type": "Module",
|
||||
"span": {
|
||||
"start": 0,
|
||||
"end": 37,
|
||||
"ctxt": 0
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "VariableDeclaration",
|
||||
"span": {
|
||||
"start": 0,
|
||||
"end": 37,
|
||||
"ctxt": 0
|
||||
},
|
||||
"kind": "const",
|
||||
"declare": false,
|
||||
"declarations": [
|
||||
{
|
||||
"type": "VariableDeclarator",
|
||||
"span": {
|
||||
"start": 6,
|
||||
"end": 37,
|
||||
"ctxt": 0
|
||||
},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"span": {
|
||||
"start": 6,
|
||||
"end": 9,
|
||||
"ctxt": 0
|
||||
},
|
||||
"value": "bar",
|
||||
"optional": false
|
||||
},
|
||||
"init": {
|
||||
"type": "TsAsExpression",
|
||||
"span": {
|
||||
"start": 12,
|
||||
"end": 15,
|
||||
"ctxt": 0
|
||||
},
|
||||
"expression": {
|
||||
"type": "Identifier",
|
||||
"span": {
|
||||
"start": 12,
|
||||
"end": 15,
|
||||
"ctxt": 0
|
||||
},
|
||||
"value": "bas",
|
||||
"optional": false
|
||||
},
|
||||
"typeAnnotation": {
|
||||
"type": "TsTypeQuery",
|
||||
"span": {
|
||||
"start": 19,
|
||||
"end": 37,
|
||||
"ctxt": 0
|
||||
},
|
||||
"exprName": {
|
||||
"type": "TsQualifiedName",
|
||||
"left": {
|
||||
"type": "Identifier",
|
||||
"span": {
|
||||
"start": 26,
|
||||
"end": 30,
|
||||
"ctxt": 0
|
||||
},
|
||||
"value": "beep",
|
||||
"optional": false
|
||||
},
|
||||
"right": {
|
||||
"type": "Identifier",
|
||||
"span": {
|
||||
"start": 31,
|
||||
"end": 37,
|
||||
"ctxt": 0
|
||||
},
|
||||
"value": "delete",
|
||||
"optional": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definite": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -716,7 +716,7 @@ fn make_ref_ident(decls: &mut Vec<VarDeclarator>, init: Option<Box<Expr>>) -> Id
|
||||
|
||||
fn make_ref_prop_expr(ref_ident: &Ident, prop: Box<Expr>, mut computed: bool) -> Expr {
|
||||
computed |= match *prop {
|
||||
Expr::Lit(Lit::Num(..)) => true,
|
||||
Expr::Lit(Lit::Num(..)) | Expr::Lit(Lit::Str(..)) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
@ -535,3 +535,12 @@ export const A = ref[0], B = ref[1], C = ref[2];
|
||||
var ref1 = [4, 5, 6];
|
||||
export const E = ref[0], D = ref[1], F = ref[2];"
|
||||
);
|
||||
|
||||
test!(
|
||||
::swc_ecma_parser::Syntax::default(),
|
||||
|_| tr(),
|
||||
issue_336,
|
||||
"const { 'foo-bar': fooBar } = baz;",
|
||||
"const ref = baz ? baz : _throw(new TypeError(\"Cannot destructure 'undefined' or 'null'\")), \
|
||||
fooBar = ref['foo-bar'];"
|
||||
);
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
use ast::*;
|
||||
use fxhash::FxHashSet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::hash_map::Entry, iter};
|
||||
use std::iter;
|
||||
use swc_common::{Fold, FoldWith, Mark, VisitWith, DUMMY_SP};
|
||||
|
||||
#[cfg(test)]
|
||||
@ -552,193 +552,9 @@ impl Fold<Prop> for Amd {
|
||||
|
||||
impl Fold<Expr> for Amd {
|
||||
fn fold(&mut self, expr: Expr) -> Expr {
|
||||
let exports_ident = self.exports.0.clone();
|
||||
let top_level = self.in_top_level;
|
||||
|
||||
macro_rules! entry {
|
||||
($i:expr) => {
|
||||
self.scope
|
||||
.exported_vars
|
||||
.entry(($i.sym.clone(), $i.span.ctxt()))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! chain_assign {
|
||||
($entry:expr, $e:expr) => {{
|
||||
let mut e = $e;
|
||||
for i in $entry.get() {
|
||||
e = box Expr::Assign(AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
left: PatOrExpr::Expr(
|
||||
box exports_ident
|
||||
.clone()
|
||||
.member(Ident::new(i.0.clone(), DUMMY_SP.with_ctxt(i.1))),
|
||||
),
|
||||
op: op!("="),
|
||||
right: e,
|
||||
});
|
||||
}
|
||||
e
|
||||
}};
|
||||
}
|
||||
|
||||
match expr {
|
||||
Expr::Ident(i) => {
|
||||
let v = self.scope.idents.get(&(i.sym.clone(), i.span.ctxt()));
|
||||
match v {
|
||||
None => return Expr::Ident(i),
|
||||
Some((src, prop)) => {
|
||||
let (ident, span) = self
|
||||
.scope
|
||||
.imports
|
||||
.get(src)
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap();
|
||||
|
||||
let obj = {
|
||||
let ident = Ident::new(ident.clone(), *span);
|
||||
|
||||
Expr::Ident(ident)
|
||||
};
|
||||
|
||||
if *prop == js_word!("") {
|
||||
// import * as foo from 'foo';
|
||||
obj
|
||||
} else {
|
||||
obj.member(Ident::new(prop.clone(), DUMMY_SP))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Expr::Member(e) => {
|
||||
if e.computed {
|
||||
Expr::Member(MemberExpr {
|
||||
obj: e.obj.fold_with(self),
|
||||
prop: e.prop.fold_with(self),
|
||||
..e
|
||||
})
|
||||
} else {
|
||||
Expr::Member(MemberExpr {
|
||||
obj: e.obj.fold_with(self),
|
||||
..e
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Expr::Update(UpdateExpr {
|
||||
span,
|
||||
arg: box Expr::Ident(arg),
|
||||
op,
|
||||
prefix,
|
||||
}) => {
|
||||
let entry = entry!(arg);
|
||||
|
||||
match entry {
|
||||
Entry::Occupied(entry) => {
|
||||
let e = chain_assign!(
|
||||
entry,
|
||||
box Expr::Assign(AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
left: PatOrExpr::Pat(box Pat::Ident(arg.clone())),
|
||||
op: op!("="),
|
||||
right: box Expr::Bin(BinExpr {
|
||||
span: DUMMY_SP,
|
||||
left: box Expr::Unary(UnaryExpr {
|
||||
span: DUMMY_SP,
|
||||
op: op!(unary, "+"),
|
||||
arg: box Expr::Ident(arg)
|
||||
}),
|
||||
op: match op {
|
||||
op!("++") => op!(bin, "+"),
|
||||
op!("--") => op!(bin, "-"),
|
||||
},
|
||||
right: box Expr::Lit(Lit::Num(Number {
|
||||
span: DUMMY_SP,
|
||||
value: 1.0,
|
||||
})),
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
*e
|
||||
}
|
||||
_ => {
|
||||
return Expr::Update(UpdateExpr {
|
||||
span,
|
||||
arg: box Expr::Ident(arg),
|
||||
op,
|
||||
prefix,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Expr::Assign(mut expr) => {
|
||||
//
|
||||
expr.right = expr.right.fold_with(self);
|
||||
|
||||
match expr.left {
|
||||
PatOrExpr::Pat(box Pat::Ident(ref i)) => {
|
||||
let entry = entry!(i);
|
||||
|
||||
match entry {
|
||||
Entry::Occupied(entry) => {
|
||||
let e = chain_assign!(entry, box Expr::Assign(expr));
|
||||
|
||||
*e
|
||||
}
|
||||
_ => {
|
||||
return Expr::Assign(AssignExpr {
|
||||
left: expr.left,
|
||||
..expr
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let mut found = vec![];
|
||||
let mut v = DestructuringFinder { found: &mut found };
|
||||
expr.left.visit_with(&mut v);
|
||||
if v.found.is_empty() {
|
||||
return Expr::Assign(AssignExpr {
|
||||
left: expr.left,
|
||||
..expr
|
||||
});
|
||||
}
|
||||
|
||||
let mut exprs = iter::once(box Expr::Assign(expr))
|
||||
.chain(
|
||||
found
|
||||
.into_iter()
|
||||
.map(|var| Ident::new(var.0, var.1))
|
||||
.filter_map(|i| {
|
||||
let entry = match entry!(i) {
|
||||
Entry::Occupied(entry) => entry,
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let e = chain_assign!(entry, box Expr::Ident(i));
|
||||
|
||||
// exports.name = x
|
||||
Some(e)
|
||||
}),
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
if exprs.len() == 1 {
|
||||
return *exprs.pop().unwrap();
|
||||
}
|
||||
|
||||
Expr::Seq(SeqExpr {
|
||||
span: DUMMY_SP,
|
||||
exprs,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => expr.fold_children(self),
|
||||
}
|
||||
Scope::fold_expr(self, self.exports.0.clone(), top_level, expr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,22 @@ fn tr(config: Config) -> impl Fold<Module> {
|
||||
chain_at!(Module, resolver(), amd(config))
|
||||
}
|
||||
|
||||
test!(
|
||||
syntax(),
|
||||
|_| tr(Config {
|
||||
..Default::default()
|
||||
}),
|
||||
issue_335,
|
||||
"import bar from 'bar';
|
||||
|
||||
obj[bar('bas')] = '123'",
|
||||
"define(['bar'], function(_bar) {
|
||||
'use strict';
|
||||
_bar = _interopRequireDefault(_bar);
|
||||
obj[_bar.default('bas')] = '123';
|
||||
});"
|
||||
);
|
||||
|
||||
test!(
|
||||
syntax(),
|
||||
|_| tr(Config {
|
||||
|
@ -11,6 +11,20 @@ fn tr(config: Config) -> impl Fold<Module> {
|
||||
chain!(resolver(), common_js(config))
|
||||
}
|
||||
|
||||
test!(
|
||||
syntax(),
|
||||
|_| tr(Config {
|
||||
..Default::default()
|
||||
}),
|
||||
issue_335,
|
||||
"import bar from 'bar';
|
||||
|
||||
obj[bar('bas')] = '123'",
|
||||
"'use strict';
|
||||
var _bar = _interopRequireDefault(require('bar'));
|
||||
obj[_bar.default('bas')] = '123';"
|
||||
);
|
||||
|
||||
test!(
|
||||
syntax(),
|
||||
|_| tr(Config {
|
||||
|
@ -9,6 +9,38 @@ fn tr(tester: &mut crate::tests::Tester, config: Config) -> impl Fold<Module> {
|
||||
chain!(resolver(), umd(tester.cm.clone(), config))
|
||||
}
|
||||
|
||||
test!(
|
||||
syntax(),
|
||||
|tester| tr(
|
||||
tester,
|
||||
Config {
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
issue_335,
|
||||
"import bar from 'bar';
|
||||
|
||||
obj[bar('bas')] = '123'",
|
||||
"(function(global, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['bar'], factory);
|
||||
} else if (typeof exports !== 'undefined') {
|
||||
factory(require('bar'));
|
||||
} else {
|
||||
var mod = {
|
||||
exports: {
|
||||
}
|
||||
};
|
||||
factory(global.bar);
|
||||
global.input = mod.exports;
|
||||
}
|
||||
})(this, function(_bar) {
|
||||
'use strict';
|
||||
_bar = _interopRequireDefault(_bar);
|
||||
obj[_bar.default('bas')] = '123';
|
||||
});"
|
||||
);
|
||||
|
||||
test!(
|
||||
syntax(),
|
||||
|tester| tr(
|
||||
|
@ -518,6 +518,7 @@ impl Scope {
|
||||
}
|
||||
|
||||
Expr::Assign(mut expr) => {
|
||||
expr.left = expr.left.fold_with(folder);
|
||||
expr.right = expr.right.fold_with(folder);
|
||||
|
||||
let mut found = vec![];
|
||||
|
Loading…
Reference in New Issue
Block a user