mirror of
https://github.com/swc-project/swc.git
synced 2024-11-24 02:06:08 +03:00
Fix Bugs (#205)
swc_ecma_codegen: - escape characters (#204) swc_ecma_parser: - fix parsing of `<!--` swc_ecma_transforms: - promote VarCollector to crate-level utility - fix es3::member_expr_lits (#206) - fix es2015::duplicate_keys pass (#203) - improve fixer (paren for assignment) (#201) - improve fixer (arrow expression) (#207) - make typescript pass strip out type-only exports (#196)
This commit is contained in:
parent
c1a3cc53c1
commit
b27829825e
@ -338,7 +338,16 @@ impl<'a> Emitter<'a> {
|
||||
// self.wr.write_str_lit(node.span, &s)?;
|
||||
// return Ok(());
|
||||
// }
|
||||
let value = node.value.replace("\\", "\\\\").replace("\n", "\\n");
|
||||
let value = node
|
||||
.value
|
||||
.replace("\\", "\\\\")
|
||||
.replace('\u{0008}', "\\b")
|
||||
.replace('\u{000C}', "\\f")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\t", "\\t")
|
||||
.replace('\u{000B}', "\\v")
|
||||
.replace("\0", "\\0");
|
||||
// let value = node.value.replace("\n", "\\n");
|
||||
|
||||
if !node.value.contains("'") {
|
||||
|
@ -86,4 +86,15 @@ mod tests {
|
||||
"import colors, { color } from 'patterns/colors';",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_204_01() {
|
||||
assert_min(r#"'\r\n';"#, r#"'\r\n';"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_204_02() {
|
||||
assert_min(r#"const a = fn() + '\r\n';"#, r#"const a=fn()+'\r\n';"#);
|
||||
}
|
||||
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
||||
(' ');
|
||||
('\t');
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
||||
a('');
|
||||
a('\v');
|
||||
|
@ -59,16 +59,16 @@ impl<'a, I: Input> Parser<'a, I> {
|
||||
}
|
||||
|
||||
pub fn parse_script(&mut self) -> PResult<'a, Script> {
|
||||
let start = cur_pos!();
|
||||
|
||||
let shebang = self.parse_shebang()?;
|
||||
|
||||
let ctx = Context {
|
||||
module: false,
|
||||
..self.ctx()
|
||||
};
|
||||
self.set_ctx(ctx);
|
||||
|
||||
let start = cur_pos!();
|
||||
|
||||
let shebang = self.parse_shebang()?;
|
||||
|
||||
self.parse_block_body(true, true, None).map(|body| Script {
|
||||
span: span!(start),
|
||||
body,
|
||||
@ -77,9 +77,6 @@ impl<'a, I: Input> Parser<'a, I> {
|
||||
}
|
||||
|
||||
pub fn parse_module(&mut self) -> PResult<'a, Module> {
|
||||
let start = cur_pos!();
|
||||
let shebang = self.parse_shebang()?;
|
||||
|
||||
//TODO: parse() -> PResult<'a, Program>
|
||||
let ctx = Context {
|
||||
module: true,
|
||||
@ -89,6 +86,9 @@ impl<'a, I: Input> Parser<'a, I> {
|
||||
// Module code is always in strict mode
|
||||
self.set_ctx(ctx);
|
||||
|
||||
let start = cur_pos!();
|
||||
let shebang = self.parse_shebang()?;
|
||||
|
||||
self.parse_block_body(true, true, None).map(|body| Module {
|
||||
span: span!(start),
|
||||
body,
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/ba2d36d35efa68ec.js:1:6
|
||||
error: Unexpected token None
|
||||
--> $DIR/tests/test262-parser/fail/ba2d36d35efa68ec.js:1:5
|
||||
|
|
||||
1 | a -->
|
||||
| ^
|
||||
| ^
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
error: Unexpected eof
|
||||
--> $DIR/tests/test262-parser/fail/d942f64886578d87.module.js:1:7
|
||||
error: Expected Word(from), got None
|
||||
--> $DIR/tests/test262-parser/fail/d942f64886578d87.module.js:1:1
|
||||
|
|
||||
1 | import
|
||||
| ^
|
||||
| ^^^^^^
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
export type Link = { key: string; text: string };
|
@ -0,0 +1,186 @@
|
||||
Module {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
0
|
||||
),
|
||||
hi: BytePos(
|
||||
49
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
body: [
|
||||
ModuleDecl(
|
||||
ExportDecl(
|
||||
TsTypeAlias(
|
||||
TsTypeAliasDecl {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
7
|
||||
),
|
||||
hi: BytePos(
|
||||
49
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
declare: false,
|
||||
id: Ident {
|
||||
sym: Link,
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
12
|
||||
),
|
||||
hi: BytePos(
|
||||
16
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: None,
|
||||
optional: false
|
||||
},
|
||||
type_params: None,
|
||||
type_ann: TsTypeLit(
|
||||
TsTypeLit {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
19
|
||||
),
|
||||
hi: BytePos(
|
||||
48
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
members: [
|
||||
TsPropertySignature(
|
||||
TsPropertySignature {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
21
|
||||
),
|
||||
hi: BytePos(
|
||||
33
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
readonly: false,
|
||||
key: Ident(
|
||||
Ident {
|
||||
sym: key,
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
21
|
||||
),
|
||||
hi: BytePos(
|
||||
24
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: None,
|
||||
optional: false
|
||||
}
|
||||
),
|
||||
computed: false,
|
||||
optional: false,
|
||||
init: None,
|
||||
params: [],
|
||||
type_ann: Some(
|
||||
TsTypeAnn {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
24
|
||||
),
|
||||
hi: BytePos(
|
||||
32
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: TsKeywordType(
|
||||
TsKeywordType {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
26
|
||||
),
|
||||
hi: BytePos(
|
||||
32
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
kind: TsStringKeyword
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
type_params: None
|
||||
}
|
||||
),
|
||||
TsPropertySignature(
|
||||
TsPropertySignature {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
34
|
||||
),
|
||||
hi: BytePos(
|
||||
46
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
readonly: false,
|
||||
key: Ident(
|
||||
Ident {
|
||||
sym: text,
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
34
|
||||
),
|
||||
hi: BytePos(
|
||||
38
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: None,
|
||||
optional: false
|
||||
}
|
||||
),
|
||||
computed: false,
|
||||
optional: false,
|
||||
init: None,
|
||||
params: [],
|
||||
type_ann: Some(
|
||||
TsTypeAnn {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
38
|
||||
),
|
||||
hi: BytePos(
|
||||
46
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: TsKeywordType(
|
||||
TsKeywordType {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
40
|
||||
),
|
||||
hi: BytePos(
|
||||
46
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
kind: TsStringKeyword
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
type_params: None
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
],
|
||||
shebang: None
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
type Link = { key: string; text: string };
|
||||
export { Link };
|
@ -0,0 +1,232 @@
|
||||
Module {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
0
|
||||
),
|
||||
hi: BytePos(
|
||||
59
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
body: [
|
||||
Stmt(
|
||||
Decl(
|
||||
TsTypeAlias(
|
||||
TsTypeAliasDecl {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
0
|
||||
),
|
||||
hi: BytePos(
|
||||
42
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
declare: false,
|
||||
id: Ident {
|
||||
sym: Link,
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
5
|
||||
),
|
||||
hi: BytePos(
|
||||
9
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: None,
|
||||
optional: false
|
||||
},
|
||||
type_params: None,
|
||||
type_ann: TsTypeLit(
|
||||
TsTypeLit {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
12
|
||||
),
|
||||
hi: BytePos(
|
||||
41
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
members: [
|
||||
TsPropertySignature(
|
||||
TsPropertySignature {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
14
|
||||
),
|
||||
hi: BytePos(
|
||||
26
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
readonly: false,
|
||||
key: Ident(
|
||||
Ident {
|
||||
sym: key,
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
14
|
||||
),
|
||||
hi: BytePos(
|
||||
17
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: None,
|
||||
optional: false
|
||||
}
|
||||
),
|
||||
computed: false,
|
||||
optional: false,
|
||||
init: None,
|
||||
params: [],
|
||||
type_ann: Some(
|
||||
TsTypeAnn {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
17
|
||||
),
|
||||
hi: BytePos(
|
||||
25
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: TsKeywordType(
|
||||
TsKeywordType {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
19
|
||||
),
|
||||
hi: BytePos(
|
||||
25
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
kind: TsStringKeyword
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
type_params: None
|
||||
}
|
||||
),
|
||||
TsPropertySignature(
|
||||
TsPropertySignature {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
27
|
||||
),
|
||||
hi: BytePos(
|
||||
39
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
readonly: false,
|
||||
key: Ident(
|
||||
Ident {
|
||||
sym: text,
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
27
|
||||
),
|
||||
hi: BytePos(
|
||||
31
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: None,
|
||||
optional: false
|
||||
}
|
||||
),
|
||||
computed: false,
|
||||
optional: false,
|
||||
init: None,
|
||||
params: [],
|
||||
type_ann: Some(
|
||||
TsTypeAnn {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
31
|
||||
),
|
||||
hi: BytePos(
|
||||
39
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: TsKeywordType(
|
||||
TsKeywordType {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
33
|
||||
),
|
||||
hi: BytePos(
|
||||
39
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
kind: TsStringKeyword
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
type_params: None
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
ModuleDecl(
|
||||
ExportNamed(
|
||||
NamedExport {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
43
|
||||
),
|
||||
hi: BytePos(
|
||||
59
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
specifiers: [
|
||||
Named(
|
||||
NamedExportSpecifier {
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
52
|
||||
),
|
||||
hi: BytePos(
|
||||
56
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
orig: Ident {
|
||||
sym: Link,
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
52
|
||||
),
|
||||
hi: BytePos(
|
||||
56
|
||||
),
|
||||
ctxt: #0
|
||||
},
|
||||
type_ann: None,
|
||||
optional: false
|
||||
},
|
||||
exported: None
|
||||
}
|
||||
)
|
||||
],
|
||||
src: None
|
||||
}
|
||||
)
|
||||
)
|
||||
],
|
||||
shebang: None
|
||||
}
|
@ -39,6 +39,12 @@ struct PropFolder {
|
||||
setter_props: FxHashSet<JsWord>,
|
||||
}
|
||||
|
||||
impl Fold<Expr> for PropFolder {
|
||||
fn fold(&mut self, node: Expr) -> Expr {
|
||||
node
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<Prop> for PropFolder {
|
||||
fn fold(&mut self, prop: Prop) -> Prop {
|
||||
match prop {
|
||||
@ -81,6 +87,11 @@ impl Fold<Prop> for PropFolder {
|
||||
struct PropNameFolder<'a> {
|
||||
props: &'a mut FxHashSet<JsWord>,
|
||||
}
|
||||
impl<'a> Fold<Expr> for PropNameFolder<'a> {
|
||||
fn fold(&mut self, node: Expr) -> Expr {
|
||||
node
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Fold<PropName> for PropNameFolder<'a> {
|
||||
fn fold(&mut self, name: PropName) -> PropName {
|
||||
|
@ -1,5 +1,37 @@
|
||||
use super::*;
|
||||
|
||||
test!(
|
||||
::swc_ecma_parser::Syntax::default(),
|
||||
|_| DuplicateKeys,
|
||||
issue_203,
|
||||
r#"
|
||||
const obj = {};
|
||||
|
||||
obj.prop = {
|
||||
alpha: {
|
||||
charlie: true
|
||||
},
|
||||
beta: {
|
||||
charlie: true,
|
||||
delta: true
|
||||
}
|
||||
};
|
||||
"#,
|
||||
r#"
|
||||
const obj = {};
|
||||
|
||||
obj.prop = {
|
||||
alpha: {
|
||||
charlie: true
|
||||
},
|
||||
beta: {
|
||||
charlie: true,
|
||||
delta: true
|
||||
}
|
||||
};
|
||||
"#
|
||||
);
|
||||
|
||||
test!(
|
||||
ignore,
|
||||
::swc_ecma_parser::Syntax::default(),
|
||||
|
@ -26,17 +26,14 @@ impl Fold<MemberExpr> for MemberExprLit {
|
||||
fn fold(&mut self, e: MemberExpr) -> MemberExpr {
|
||||
let mut e = e.fold_children(self);
|
||||
|
||||
e.prop = match *e.prop {
|
||||
Expr::Lit(Lit::Str(Str {
|
||||
value: sym, span, ..
|
||||
}))
|
||||
| Expr::Ident(Ident { sym, span, .. }) => {
|
||||
if sym.is_reserved_for_es3() || !is_valid_ident(&sym) {
|
||||
macro_rules! handle {
|
||||
($sym:expr, $span:expr) => {
|
||||
if $sym.is_reserved_for_es3() || !is_valid_ident(&$sym) {
|
||||
return MemberExpr {
|
||||
computed: true,
|
||||
prop: box Expr::Lit(Lit::Str(Str {
|
||||
span,
|
||||
value: sym,
|
||||
span: $span,
|
||||
value: $sym,
|
||||
has_escape: false,
|
||||
})),
|
||||
..e
|
||||
@ -44,10 +41,21 @@ impl Fold<MemberExpr> for MemberExprLit {
|
||||
} else {
|
||||
return MemberExpr {
|
||||
computed: false,
|
||||
prop: box Expr::Ident(quote_ident!(span, sym)),
|
||||
prop: box Expr::Ident(quote_ident!($span, $sym)),
|
||||
..e
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
e.prop = match *e.prop {
|
||||
Expr::Lit(Lit::Str(Str { value, span, .. })) => handle!(value, span),
|
||||
Expr::Ident(i) => {
|
||||
if e.computed {
|
||||
box Expr::Ident(i)
|
||||
} else {
|
||||
handle!(i.sym, i.span)
|
||||
}
|
||||
}
|
||||
_ => e.prop,
|
||||
};
|
||||
@ -74,4 +82,11 @@ obj["const"] = "isKeyword";
|
||||
obj["var"] = "isKeyword";"#
|
||||
);
|
||||
|
||||
test!(
|
||||
::swc_ecma_parser::Syntax::default(),
|
||||
|_| MemberExprLit,
|
||||
issue_206,
|
||||
"const number = foo[bar1][baz1]",
|
||||
"const number = foo[bar1][baz1]"
|
||||
);
|
||||
}
|
||||
|
@ -77,6 +77,20 @@ impl Fold<VarDeclarator> for Fixer {
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<BlockStmtOrExpr> for Fixer {
|
||||
fn fold(&mut self, body: BlockStmtOrExpr) -> BlockStmtOrExpr {
|
||||
let body = body.fold_children(self);
|
||||
|
||||
match body {
|
||||
BlockStmtOrExpr::Expr(box expr @ Expr::Object(..)) => {
|
||||
BlockStmtOrExpr::Expr(box expr.wrap_with_paren())
|
||||
}
|
||||
|
||||
_ => body,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<Stmt> for Fixer {
|
||||
fn fold(&mut self, stmt: Stmt) -> Stmt {
|
||||
let stmt = match stmt {
|
||||
@ -189,6 +203,20 @@ macro_rules! array {
|
||||
array!(ArrayLit);
|
||||
// array!(ArrayPat);
|
||||
|
||||
impl Fold<KeyValueProp> for Fixer {
|
||||
fn fold(&mut self, prop: KeyValueProp) -> KeyValueProp {
|
||||
let prop = prop.fold_children(self);
|
||||
|
||||
match *prop.value {
|
||||
Expr::Seq(..) => KeyValueProp {
|
||||
value: box (*prop.value).wrap_with_paren(),
|
||||
..prop
|
||||
},
|
||||
_ => return prop,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<Expr> for Fixer {
|
||||
fn fold(&mut self, expr: Expr) -> Expr {
|
||||
fn unwrap_expr(mut e: Expr) -> Expr {
|
||||
@ -459,4 +487,14 @@ const _ref = {}, { c =( _tmp = {}, d = _extends({}, _tmp), _tmp) } = _ref;"
|
||||
identical!(issue_192, "a === true && (a = true)");
|
||||
|
||||
identical!(issue_199, "(i - 1).toString()");
|
||||
|
||||
identical!(
|
||||
issue_201_01,
|
||||
"outer = {
|
||||
inner: (_obj = {}, _defineProperty(_obj, ns.EXPORT1, true), _defineProperty(_obj, ns.EXPORT2, \
|
||||
true), _obj)
|
||||
};"
|
||||
);
|
||||
|
||||
identical!(issue_207, "a => ({x: 'xxx', y: {a}});");
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
use super::util::{
|
||||
define_es_module, define_property, has_use_strict, initialize_to_undefined, local_name_for_src,
|
||||
make_descriptor, use_strict, Exports, Scope, VarCollector,
|
||||
make_descriptor, use_strict, Exports, Scope,
|
||||
};
|
||||
use crate::{
|
||||
pass::Pass,
|
||||
util::{prepend_stmts, DestructuringFinder, ExprFactory, State},
|
||||
util::{prepend_stmts, var::VarCollector, DestructuringFinder, ExprFactory, State},
|
||||
};
|
||||
use ast::*;
|
||||
use fxhash::FxHashSet;
|
||||
|
@ -1,10 +1,10 @@
|
||||
use super::util::{
|
||||
define_es_module, define_property, has_use_strict, initialize_to_undefined, make_descriptor,
|
||||
make_require_call, use_strict, Scope, VarCollector,
|
||||
make_require_call, use_strict, Scope,
|
||||
};
|
||||
use crate::{
|
||||
pass::Pass,
|
||||
util::{undefined, DestructuringFinder, ExprFactory, State},
|
||||
util::{undefined, var::VarCollector, DestructuringFinder, ExprFactory, State},
|
||||
};
|
||||
use ast::*;
|
||||
use fxhash::FxHashSet;
|
||||
|
@ -2,11 +2,11 @@ use self::config::BuiltConfig;
|
||||
pub use self::config::Config;
|
||||
use super::util::{
|
||||
define_es_module, define_property, has_use_strict, initialize_to_undefined, local_name_for_src,
|
||||
make_descriptor, make_require_call, use_strict, Exports, Scope, VarCollector,
|
||||
make_descriptor, make_require_call, use_strict, Exports, Scope,
|
||||
};
|
||||
use crate::{
|
||||
pass::Pass,
|
||||
util::{prepend_stmts, DestructuringFinder, ExprFactory, State},
|
||||
util::{prepend_stmts, var::VarCollector, DestructuringFinder, ExprFactory, State},
|
||||
};
|
||||
use ast::*;
|
||||
use fxhash::FxHashSet;
|
||||
|
@ -4,7 +4,7 @@ use fxhash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
use inflector::Inflector;
|
||||
use std::iter;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{Mark, Span, SyntaxContext, Visit, VisitWith, DUMMY_SP};
|
||||
use swc_common::{Mark, Span, SyntaxContext, DUMMY_SP};
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(super) struct Scope {
|
||||
@ -420,39 +420,6 @@ pub(super) fn make_descriptor(get_expr: Box<Expr>) -> ObjectLit {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct VarCollector<'a> {
|
||||
pub to: &'a mut Vec<(JsWord, SyntaxContext)>,
|
||||
}
|
||||
|
||||
impl<'a> Visit<VarDeclarator> for VarCollector<'a> {
|
||||
fn visit(&mut self, node: &VarDeclarator) {
|
||||
node.name.visit_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit<Ident> for VarCollector<'a> {
|
||||
fn visit(&mut self, i: &Ident) {
|
||||
self.to.push((i.sym.clone(), i.span.ctxt()))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! var_noop {
|
||||
($T:path) => {
|
||||
impl<'a> Visit<$T> for VarCollector<'a> {
|
||||
fn visit(&mut self, _: &$T) {}
|
||||
}
|
||||
};
|
||||
|
||||
($T:path, $($rest:tt)*) => {
|
||||
var_noop!($T);
|
||||
var_noop!($($rest)*);
|
||||
};
|
||||
}
|
||||
|
||||
var_noop!(Expr, ArrowExpr, Function, Constructor);
|
||||
|
||||
var_noop!(TsType, TsTypeAnn, TsTypeParam);
|
||||
|
||||
/// Private `_exports` ident.
|
||||
pub(super) struct Exports(pub Ident);
|
||||
|
||||
|
@ -1,17 +1,95 @@
|
||||
use crate::{
|
||||
pass::Pass,
|
||||
util::{prepend_stmts, ExprFactory},
|
||||
util::{prepend_stmts, var::VarCollector, ExprFactory, State},
|
||||
};
|
||||
use ast::*;
|
||||
use swc_common::{util::move_map::MoveMap, Fold, FoldWith, Spanned, DUMMY_SP};
|
||||
use fxhash::FxHashMap;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{
|
||||
util::move_map::MoveMap, Fold, FoldWith, Spanned, SyntaxContext, VisitWith, DUMMY_SP,
|
||||
};
|
||||
|
||||
/// Strips type annotations out.
|
||||
pub fn strip() -> impl Pass + Clone + Copy {
|
||||
Strip
|
||||
pub fn strip() -> impl Pass + Clone {
|
||||
Strip::default()
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Strip;
|
||||
#[derive(Default, Clone)]
|
||||
struct Strip {
|
||||
non_top_level: State<bool>,
|
||||
scope: State<Scope>,
|
||||
}
|
||||
|
||||
impl Strip {
|
||||
fn handle_decl(&mut self, decl: &Decl) {
|
||||
// We don't care about stuffs which cannot be exported
|
||||
if self.non_top_level.value {
|
||||
return;
|
||||
}
|
||||
|
||||
macro_rules! store {
|
||||
($sym:expr, $ctxt:expr, $concrete:expr) => {{
|
||||
let entry = self
|
||||
.scope
|
||||
.value
|
||||
.decls
|
||||
.entry(($sym.clone(), $ctxt))
|
||||
.or_default();
|
||||
|
||||
if $concrete {
|
||||
entry.has_concrete = true
|
||||
} else {
|
||||
entry.has_type = true;
|
||||
}
|
||||
}};
|
||||
}
|
||||
match *decl {
|
||||
Decl::Class(ClassDecl { ref ident, .. }) | Decl::Fn(FnDecl { ref ident, .. }) => {
|
||||
store!(ident.sym, ident.span.ctxt(), true);
|
||||
}
|
||||
|
||||
Decl::Var(ref var) => {
|
||||
let mut names = vec![];
|
||||
var.decls.visit_with(&mut VarCollector { to: &mut names });
|
||||
|
||||
for name in names {
|
||||
store!(name.0, name.1, true);
|
||||
}
|
||||
}
|
||||
|
||||
Decl::TsEnum(TsEnumDecl { ref id, .. })
|
||||
| Decl::TsInterface(TsInterfaceDecl { ref id, .. })
|
||||
| Decl::TsModule(TsModuleDecl {
|
||||
id: TsModuleName::Ident(ref id),
|
||||
..
|
||||
})
|
||||
| Decl::TsTypeAlias(TsTypeAliasDecl { ref id, .. }) => {
|
||||
store!(id.sym, id.span.ctxt(), false)
|
||||
}
|
||||
|
||||
Decl::TsModule(TsModuleDecl {
|
||||
id:
|
||||
TsModuleName::Str(Str {
|
||||
ref value, span, ..
|
||||
}),
|
||||
..
|
||||
}) => store!(value, span.ctxt(), false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Scope {
|
||||
decls: FxHashMap<(JsWord, SyntaxContext), DeclInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct DeclInfo {
|
||||
/// interface / type alias
|
||||
has_type: bool,
|
||||
/// Var, Fn, Class
|
||||
has_concrete: bool,
|
||||
}
|
||||
|
||||
impl Fold<Constructor> for Strip {
|
||||
fn fold(&mut self, c: Constructor) -> Constructor {
|
||||
@ -65,15 +143,19 @@ impl Fold<Constructor> for Strip {
|
||||
|
||||
impl Fold<Vec<ModuleItem>> for Strip {
|
||||
fn fold(&mut self, items: Vec<ModuleItem>) -> Vec<ModuleItem> {
|
||||
let items = items.fold_children(self);
|
||||
|
||||
items.move_flat_map(|item| match item {
|
||||
ModuleItem::Stmt(Stmt::Empty(..))
|
||||
| ModuleItem::Stmt(Stmt::Decl(Decl::TsEnum(..)))
|
||||
ModuleItem::Stmt(Stmt::Empty(..)) => None,
|
||||
|
||||
ModuleItem::Stmt(Stmt::Decl(Decl::TsEnum(..)))
|
||||
| ModuleItem::Stmt(Stmt::Decl(Decl::TsInterface(..)))
|
||||
| ModuleItem::Stmt(Stmt::Decl(Decl::TsModule(..)))
|
||||
| ModuleItem::Stmt(Stmt::Decl(Decl::TsTypeAlias(..)))
|
||||
| ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(Decl::TsEnum(..)))
|
||||
| ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(Decl::TsInterface(..)))
|
||||
| ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(Decl::TsModule(..)))
|
||||
| ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(Decl::TsTypeAlias(..)))
|
||||
| ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(
|
||||
ExportDefaultDecl::TsInterfaceDecl(..),
|
||||
))
|
||||
@ -104,12 +186,50 @@ impl Fold<Vec<ModuleItem>> for Strip {
|
||||
ModuleItem::ModuleDecl(ModuleDecl::TsExportAssignment(export)) => Some(
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(export.expr).fold_with(self)),
|
||||
),
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(mut export)) => {
|
||||
// if specifier become empty, we remove export statement.
|
||||
|
||||
export.specifiers.retain(|s| match *s {
|
||||
ExportSpecifier::Named(NamedExportSpecifier { ref orig, .. }) => {
|
||||
if let Some(e) = self
|
||||
.scope
|
||||
.value
|
||||
.decls
|
||||
.get(&(orig.sym.clone(), orig.span.ctxt()))
|
||||
{
|
||||
e.has_concrete
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
});
|
||||
if export.specifiers.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
||||
NamedExport { ..export },
|
||||
)))
|
||||
}
|
||||
|
||||
_ => Some(item.fold_with(self)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<Decl> for Strip {
|
||||
fn fold(&mut self, decl: Decl) -> Decl {
|
||||
self.handle_decl(&decl);
|
||||
|
||||
let old = self.non_top_level;
|
||||
self.non_top_level = true.into();
|
||||
let decl = decl.fold_children(self);
|
||||
self.non_top_level = old;
|
||||
decl
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<Stmt> for Strip {
|
||||
fn fold(&mut self, stmt: Stmt) -> Stmt {
|
||||
let stmt = stmt.fold_children(self);
|
||||
@ -215,4 +335,28 @@ mod tests {
|
||||
to!(export_import, "export import A = B", "export { B as A }");
|
||||
|
||||
to!(export_equals, "export = Foo", "export default Foo");
|
||||
|
||||
to!(
|
||||
issue_196_01,
|
||||
"export type Link = { key: string; text: string };",
|
||||
""
|
||||
);
|
||||
|
||||
to!(
|
||||
issue_196_02,
|
||||
"type Link = { key: string; text: string };
|
||||
export { Link };",
|
||||
""
|
||||
);
|
||||
|
||||
to!(
|
||||
issue_196_03,
|
||||
"type Link = { key: string; text: string };
|
||||
const Link = 'Boo';
|
||||
export { Link };",
|
||||
"const Link = 'Boo';
|
||||
export { Link };"
|
||||
);
|
||||
|
||||
// TODO: Test function / variable hoisting
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ pub(crate) mod constructor;
|
||||
mod factory;
|
||||
mod state;
|
||||
mod value;
|
||||
pub(crate) mod var;
|
||||
|
||||
pub(crate) struct ThisVisitor {
|
||||
found: bool,
|
||||
|
36
ecmascript/transforms/src/util/var.rs
Normal file
36
ecmascript/transforms/src/util/var.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use ast::*;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{SyntaxContext, Visit, VisitWith};
|
||||
|
||||
pub(crate) struct VarCollector<'a> {
|
||||
pub to: &'a mut Vec<(JsWord, SyntaxContext)>,
|
||||
}
|
||||
|
||||
impl<'a> Visit<VarDeclarator> for VarCollector<'a> {
|
||||
fn visit(&mut self, node: &VarDeclarator) {
|
||||
node.name.visit_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit<Ident> for VarCollector<'a> {
|
||||
fn visit(&mut self, i: &Ident) {
|
||||
self.to.push((i.sym.clone(), i.span.ctxt()))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! var_noop {
|
||||
($T:path) => {
|
||||
impl<'a> Visit<$T> for VarCollector<'a> {
|
||||
fn visit(&mut self, _: &$T) {}
|
||||
}
|
||||
};
|
||||
|
||||
($T:path, $($rest:tt)*) => {
|
||||
var_noop!($T);
|
||||
var_noop!($($rest)*);
|
||||
};
|
||||
}
|
||||
|
||||
var_noop!(Expr, ArrowExpr, Function, Constructor);
|
||||
|
||||
var_noop!(TsType, TsTypeAnn, TsTypeParam);
|
Loading…
Reference in New Issue
Block a user