fix(es/typescript): Fix handling of references in a TypeScript enum (#3163)

This commit is contained in:
magic-akari 2022-01-02 03:51:39 +08:00 committed by GitHub
parent 360ad7b41c
commit e02307d4c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 5 deletions

View File

@ -9,16 +9,19 @@ use swc_common::{
Mark, SourceMap, Span, Spanned, SyntaxContext, DUMMY_SP,
};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::ext::ExprRefExt;
use swc_ecma_transforms_react::{parse_expr_for_jsx, JsxDirectives};
use swc_ecma_utils::{
constructor::inject_after_super, default_constructor, ident::IdentLike, member_expr, prepend,
private_ident, prop_name_to_expr, quote_ident, replace_ident, var::VarCollector, ExprFactory,
Id, ModuleItemLike, StmtLike,
};
use swc_ecma_visit::{as_folder, Fold, Visit, VisitMut, VisitMutWith, VisitWith};
use swc_ecma_visit::{
as_folder, noop_visit_mut_type, Fold, Visit, VisitMut, VisitMutWith, VisitWith,
};
/// Value does not contain TsLit::Bool
type EnumValues = AHashMap<JsWord, TsLit>;
type EnumValues = AHashMap<JsWord, Option<TsLit>>;
#[derive(Debug, Serialize, Deserialize)]
#[non_exhaustive]
@ -846,7 +849,7 @@ where
}
Expr::Ident(ref id) => {
if let Some(v) = values.get(&id.sym) {
if let Some(Some(v)) = values.get(&id.sym) {
return Ok(v.clone());
}
//
@ -963,7 +966,7 @@ where
TsEnumMemberId::Ident(i) => i.sym.clone(),
TsEnumMemberId::Str(s) => s.value.clone(),
},
val.clone(),
Some(val.clone()),
);
match val {
@ -978,7 +981,24 @@ where
})
.or_else(|err| match &m.init {
None => Err(err),
Some(v) => Ok(*v.clone()),
Some(v) => {
let mut v = *v.clone();
let mut visitor = EnumValuesVisitor {
previous: &values,
ident: &id,
};
visitor.visit_mut_expr(&mut v);
values.insert(
match &m.id {
TsEnumMemberId::Ident(i) => i.sym.clone(),
TsEnumMemberId::Str(s) => s.value.clone(),
},
None,
);
Ok(v)
}
})?;
Ok((m, val))
@ -2723,3 +2743,34 @@ fn create_prop_pat(obj: &Ident, pat: Pat) -> Pat {
Pat::Expr(..) => pat,
}
}
struct EnumValuesVisitor<'a> {
ident: &'a Ident,
previous: &'a EnumValues,
}
impl VisitMut for EnumValuesVisitor<'_> {
noop_visit_mut_type!();
fn visit_mut_expr(&mut self, expr: &mut Expr) {
match expr {
Expr::Ident(ident) if self.previous.contains_key(&ident.sym) => {
*expr = self.ident.clone().make_member(ident.clone());
}
Expr::Member(MemberExpr {
obj: ExprOrSuper::Expr(ref obj),
// prop,
..
}) if obj
.as_ident()
.and_then(|obj| self.previous.get(&obj.sym))
.is_some() =>
{
*expr = self.ident.clone().make_member(expr.clone());
}
Expr::Member(..) => {
// skip
}
_ => expr.visit_mut_children_with(self),
}
}
}

View File

@ -0,0 +1,9 @@
var x = 4;
enum Foo {
a,
b = a,
c = b + 1,
d = 1 + c * x,
e = 2 * d,
f = Foo.e * 10,
}

View File

@ -0,0 +1,11 @@
var x = 4;
var Foo;
(function(Foo) {
Foo[Foo["a"] = 0] = "a";
Foo[Foo["b"] = 0] = "b";
Foo[Foo["c"] = 1] = "c";
Foo[Foo["d"] = 1 + Foo.c * x] = "d";
Foo[Foo["e"] = 2 * Foo.d] = "e";
Foo[Foo["f"] = Foo.e * 10] = "f";
})(Foo || (Foo = {
}));

View File

@ -0,0 +1,22 @@
var x = 10;
enum Foo {
a = 10,
b = a,
c = b + x,
d = c,
}
enum Bar {
a = 1,
b = Foo.a,
E = b,
F = Math.E,
}
enum Baz {
a = 0,
b = 1,
// @ts-ignore
x = a.toString(),
}

View File

@ -0,0 +1,24 @@
var x = 10;
var Foo;
(function(Foo) {
Foo[Foo["a"] = 10] = "a";
Foo[Foo["b"] = 10] = "b";
Foo[Foo["c"] = Foo.b + x] = "c";
Foo[Foo["d"] = Foo.c] = "d";
})(Foo || (Foo = {
}));
var Bar;
(function(Bar) {
Bar[Bar["a"] = 1] = "a";
Bar[Bar["b"] = Foo.a] = "b";
Bar[Bar["E"] = Bar.b] = "E";
Bar[Bar["F"] = Math.E] = "F";
})(Bar || (Bar = {
}));
var Baz;
(function(Baz) {
Baz[Baz["a"] = 0] = "a";
Baz[Baz["b"] = 1] = "b";
Baz[Baz["x"] = Baz.a.toString()] = "x";
})(Baz || (Baz = {
}));