-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix(es/typescript): Handle TypeScript expressions in enum transformation #11769
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 8 commits
af91f1a
c9ea557
891439e
96965d9
6433532
fd25b41
d3b6400
fd53909
977d1f7
fa963a6
d2c98c1
9303595
3d75291
1062344
00d0558
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| { | ||
| "jsc": { | ||
| "parser": { | ||
| "syntax": "typescript", | ||
| "tsx": false | ||
| }, | ||
| "target": "es2024" | ||
| }, | ||
| "module": { | ||
| "type": "es6" | ||
| }, | ||
| "isModule": true | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| export enum RefType { | ||
| property = "11" as any, | ||
| event = "22" as any, | ||
| } | ||
|
|
||
| console.log(RefType.property, RefType.event); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| enum E { | ||
| A = ((B: number) => B)(2), | ||
| B = 1, | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| enum E { | ||
| A, | ||
| B, | ||
| C, | ||
| D = ((C) => { | ||
| console.log(A, B, C, F); | ||
| return 2; | ||
| })(), | ||
| F = "F", | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| export var RefType = /*#__PURE__*/ function(RefType) { | ||
| RefType["property"] = "11"; | ||
| RefType["event"] = "22"; | ||
| return RefType; | ||
| }({}); | ||
| console.log("11", "22"); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| var E = function(E) { | ||
| E[E["A"] = ((B)=>B)(2)] = "A"; | ||
| E[E["B"] = 1] = "B"; | ||
| return E; | ||
| }(E || {}); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| var E = function(E) { | ||
| E[E["A"] = 0] = "A"; | ||
| E[E["B"] = 1] = "B"; | ||
| E[E["C"] = 2] = "C"; | ||
| E[E["D"] = ((C)=>{ | ||
| console.log(E.A, E.B, C, E.F); | ||
| return 2; | ||
| })()] = "D"; | ||
| E["F"] = "F"; | ||
| return E; | ||
| }(E || {}); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| //// [constEnum2.ts] | ||
| var D, D1 = ((D = D1 || {})[D.e = 199 * Math.floor(1000 * Math.random())] = "e", D[D.f = 10 - 100 * Math.floor(Math.random() % 8)] = "f", D[D.g = 0] = "g", D); | ||
| var D, D1 = ((D = D1 || {})[D.e = 199 * Math.floor(1000 * Math.random())] = "e", D[D.f = D.d - 100 * Math.floor(Math.random() % 8)] = "f", D[D.g = 0] = "g", D); | ||
magic-akari marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1258,15 +1258,20 @@ impl VisitMut for Resolver<'_> { | |
| self.modify(&mut decl.id, DeclKind::Lexical); | ||
|
|
||
| self.with_child(ScopeKind::Block, |child| { | ||
| // add the enum member names as declared symbols for this scope | ||
| // Ex. `enum Foo { a, b = a }` | ||
| let member_names = decl.members.iter().filter_map(|m| match &m.id { | ||
| TsEnumMemberId::Ident(id) => Some((id.sym.clone(), DeclKind::Lexical)), | ||
| TsEnumMemberId::Str(_) => None, | ||
| #[cfg(swc_ast_unknown)] | ||
| _ => None, | ||
| }); | ||
| child.current.declared_symbols.extend(member_names); | ||
| // Intentionally do not predeclare enum members in the resolver. | ||
| // Enum initializers may reference other members, including quoted names whose | ||
| // text is a valid identifier: | ||
| // | ||
| // ```TypeScript | ||
| // enum E { | ||
| // A = "A", | ||
| // "B" = "B", | ||
| // C = (() => { console.log(A, B); })(), | ||
| // } | ||
| // ``` | ||
| // | ||
| // We keep those references unresolved here so the TypeScript enum transform | ||
| // can rewrite them using semantic.enum_record. | ||
|
||
|
|
||
| decl.members.visit_mut_with(child); | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1052,6 +1052,13 @@ impl Transform { | |
| && !is_export | ||
| && !self.semantic.exported_binding.contains_key(&id.to_id()); | ||
|
|
||
| let member_names = self | ||
| .semantic | ||
| .enum_record | ||
| .keys() | ||
| .map(|k| k.member_name.clone()) | ||
| .collect(); | ||
|
|
||
magic-akari marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| let member_list: Vec<_> = members | ||
| .into_iter() | ||
| .map(|m| { | ||
|
|
@@ -1063,7 +1070,18 @@ impl Transform { | |
| member_name: name.clone(), | ||
| }; | ||
|
|
||
| let value = self.semantic.enum_record.get(&key).unwrap().clone(); | ||
| let mut value = self.semantic.enum_record.get(&key).unwrap().clone(); | ||
|
|
||
| if let TsEnumRecordValue::Opaque(expr) = &mut value { | ||
| *expr = m.init.unwrap(); | ||
| expr.visit_mut_with(&mut RefRewriter { | ||
| query: EnumMemberRefQuery { | ||
| enum_id: &id.to_id(), | ||
| member_names: &member_names, | ||
| unresolved_ctxt: self.unresolved_ctxt, | ||
| }, | ||
| }); | ||
|
Comment on lines
+1088
to
+1095
|
||
| } | ||
|
|
||
| EnumMemberItem { span, name, value } | ||
| }) | ||
|
|
@@ -1817,6 +1835,46 @@ impl QueryRef for ExportQuery { | |
| } | ||
| } | ||
|
|
||
| struct EnumMemberRefQuery<'a> { | ||
| enum_id: &'a Id, | ||
| member_names: &'a FxHashSet<Atom>, | ||
| unresolved_ctxt: SyntaxContext, | ||
| } | ||
|
|
||
| impl QueryRef for EnumMemberRefQuery<'_> { | ||
| fn query_ref(&self, ident: &Ident) -> Option<Box<Expr>> { | ||
| if ident.ctxt == self.unresolved_ctxt && self.member_names.contains(&ident.sym) { | ||
| Some( | ||
| self.enum_id | ||
| .clone() | ||
| .make_member(ident.clone().into()) | ||
| .into(), | ||
| ) | ||
| } else { | ||
| None | ||
| } | ||
| } | ||
|
|
||
| fn query_lhs(&self, ident: &Ident) -> Option<Box<Expr>> { | ||
| self.query_ref(ident) | ||
| } | ||
|
|
||
| fn query_jsx(&self, ident: &Ident) -> Option<JSXElementName> { | ||
| if ident.ctxt == self.unresolved_ctxt && self.member_names.contains(&ident.sym) { | ||
| Some( | ||
| JSXMemberExpr { | ||
| span: DUMMY_SP, | ||
| obj: JSXObject::Ident(self.enum_id.clone().into()), | ||
| prop: ident.clone().into(), | ||
| } | ||
| .into(), | ||
| ) | ||
| } else { | ||
| None | ||
| } | ||
| } | ||
| } | ||
|
|
||
| struct EnumMemberItem { | ||
| span: Span, | ||
| name: Atom, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| var A = function(A) { | ||
| A[A["a"] = a] = "a"; | ||
| A[A["a"] = A.a] = "a"; | ||
| return A; | ||
| }(A || {}); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| var Foo = function(Foo) { | ||
| Foo[Foo["a"] = (class { | ||
| constructor(b){ | ||
| this.b = b; | ||
| } | ||
| }, 0)] = "a"; | ||
| return Foo; | ||
| }(Foo || {}); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| var Foo = function(Foo) { | ||
| Foo[Foo["a"] = (()=>{ | ||
| let Bar = /*#__PURE__*/ function(Bar) { | ||
| Bar["a"] = "a"; | ||
| Bar["b"] = "b"; | ||
| return Bar; | ||
| }({}); | ||
| return 0; | ||
| })()] = "a"; | ||
| return Foo; | ||
| }(Foo || {}); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| var Foo = function(Foo) { | ||
| Foo[Foo["a"] = foo('x')] = "a"; | ||
| return Foo; | ||
| }(Foo || {}); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| var RefType = /*#__PURE__*/ function(RefType) { | ||
| RefType["property"] = "11"; | ||
| RefType["event"] = "22"; | ||
| return RefType; | ||
| }(RefType || {}); |
Uh oh!
There was an error while loading. Please reload this page.