diff --git a/crates/swc_ecma_ast/src/ident.rs b/crates/swc_ecma_ast/src/ident.rs index e5bded9fa04b..97ed0ed65f58 100644 --- a/crates/swc_ecma_ast/src/ident.rs +++ b/crates/swc_ecma_ast/src/ident.rs @@ -425,6 +425,8 @@ static RESSERVED_IN_STRICT_MODE: phf::Set<&str> = phf_set!( "yield", ); +static RESSERVED_IN_STRICT_BIND: phf::Set<&str> = phf_set!("eval", "arguments",); + static RESERVED_IN_ES3: phf::Set<&str> = phf_set!( "abstract", "boolean", @@ -457,12 +459,19 @@ pub trait IdentExt: AsRef { } fn is_reserved_in_strict_bind(&self) -> bool { - ["eval", "arguments"].contains(&self.as_ref()) + RESSERVED_IN_STRICT_BIND.contains(self.as_ref()) } fn is_reserved_in_es3(&self) -> bool { RESERVED_IN_ES3.contains(self.as_ref()) } + + fn is_reserved_in_any(&self) -> bool { + RESERVED.contains(self.as_ref()) + || RESSERVED_IN_STRICT_MODE.contains(self.as_ref()) + || RESSERVED_IN_STRICT_BIND.contains(self.as_ref()) + || RESERVED_IN_ES3.contains(self.as_ref()) + } } impl IdentExt for Atom {} diff --git a/crates/swc_ecma_compat_es2022/src/class_properties/mod.rs b/crates/swc_ecma_compat_es2022/src/class_properties/mod.rs index 054745604a15..f386302ba7d1 100644 --- a/crates/swc_ecma_compat_es2022/src/class_properties/mod.rs +++ b/crates/swc_ecma_compat_es2022/src/class_properties/mod.rs @@ -1,9 +1,6 @@ use swc_common::{ - collections::{AHashMap, AHashSet}, - comments::Comments, - errors::HANDLER, - util::take::Take, - Mark, Span, Spanned, SyntaxContext, DUMMY_SP, + collections::AHashMap, comments::Comments, errors::HANDLER, util::take::Take, Mark, Span, + Spanned, SyntaxContext, DUMMY_SP, }; use swc_ecma_ast::*; use swc_ecma_transforms_base::{helper, perf::Check}; @@ -530,7 +527,6 @@ impl ClassProperties { let mut super_ident = None; class.body.visit_mut_with(&mut BrandCheckHandler { - names: &mut AHashSet::default(), private: &self.private, }); @@ -806,7 +802,13 @@ impl ClassProperties { match method.kind { MethodKind::Getter => format!("get_{}", method.key.id.sym).into(), MethodKind::Setter => format!("set_{}", method.key.id.sym).into(), - MethodKind::Method => method.key.id.sym.clone(), + MethodKind::Method => { + if method.key.id.is_reserved_in_any() { + format!("__{}", method.key.id.sym).into() + } else { + method.key.id.sym.clone() + } + } }, method .span diff --git a/crates/swc_ecma_compat_es2022/src/class_properties/private_field.rs b/crates/swc_ecma_compat_es2022/src/class_properties/private_field.rs index c72e31ca04fc..2f96a111ae04 100644 --- a/crates/swc_ecma_compat_es2022/src/class_properties/private_field.rs +++ b/crates/swc_ecma_compat_es2022/src/class_properties/private_field.rs @@ -2,10 +2,8 @@ use std::iter; use swc_atoms::JsWord; use swc_common::{ - collections::{AHashMap, AHashSet}, - errors::HANDLER, - util::take::Take, - Mark, Spanned, SyntaxContext, DUMMY_SP, + collections::AHashMap, errors::HANDLER, util::take::Take, Mark, Spanned, SyntaxContext, + DUMMY_SP, }; use swc_ecma_ast::*; use swc_ecma_transforms_base::helper; @@ -83,9 +81,6 @@ impl PrivateKind { } pub(super) struct BrandCheckHandler<'a> { - /// Private names used for brand checks. - pub names: &'a mut AHashSet, - pub private: &'a PrivateRecord, } @@ -117,8 +112,6 @@ impl VisitMut for BrandCheckHandler<'_> { } } - self.names.insert(n.id.sym.clone()); - let (mark, kind, class_name) = self.private.get(&n.id); if mark == Mark::root() { @@ -596,7 +589,11 @@ impl<'a> PrivateAccessVisitor<'a> { } let method_name = Ident::new( - n.id.sym.clone(), + if n.id.is_reserved_in_any() { + format!("__{}", n.id.sym).into() + } else { + n.id.sym.clone() + }, n.id.span.with_ctxt(SyntaxContext::empty()).apply_mark(mark), ); let ident = Ident::new(format!("_{}", n.id.sym).into(), n.id.span.apply_mark(mark)); diff --git a/crates/swc_ecma_transforms_compat/tests/__swc_snapshots__/tests/es2022_class_properties.rs/loose_keyword_method.js b/crates/swc_ecma_transforms_compat/tests/__swc_snapshots__/tests/es2022_class_properties.rs/loose_keyword_method.js new file mode 100644 index 000000000000..2dc61406e46e --- /dev/null +++ b/crates/swc_ecma_transforms_compat/tests/__swc_snapshots__/tests/es2022_class_properties.rs/loose_keyword_method.js @@ -0,0 +1,24 @@ +var _switch = /*#__PURE__*/ _class_private_field_loose_key("_switch"), _bar = /*#__PURE__*/ _class_private_field_loose_key("_bar"); +class TestCls { + foo() { + _class_private_field_loose_base(this, _bar)[_bar](); + _class_private_field_loose_base(this, _switch)[_switch](); + } + constructor(){ + Object.defineProperty(this, _switch, { + value: __switch + }); + Object.defineProperty(this, _bar, { + value: bar + }); + } +} +function __switch() { + console.log("#switch called"); +} +function bar() { + console.log("#bar called"); +} +export { TestCls }; +let a = new TestCls; +a.foo(); diff --git a/crates/swc_ecma_transforms_compat/tests/class-properties/issue-8948/input.js b/crates/swc_ecma_transforms_compat/tests/class-properties/issue-8948/input.js new file mode 100644 index 000000000000..1ac174f9e046 --- /dev/null +++ b/crates/swc_ecma_transforms_compat/tests/class-properties/issue-8948/input.js @@ -0,0 +1,16 @@ +class TestCls { + foo() { + this.#bar(); + this.#switch(); + } + #switch() { + console.log("#switch called"); + } + + #bar() { + console.log("#bar called"); + } +} + +let a = new TestCls(); +a.foo(); diff --git a/crates/swc_ecma_transforms_compat/tests/class-properties/issue-8948/output.js b/crates/swc_ecma_transforms_compat/tests/class-properties/issue-8948/output.js new file mode 100644 index 000000000000..787b18303894 --- /dev/null +++ b/crates/swc_ecma_transforms_compat/tests/class-properties/issue-8948/output.js @@ -0,0 +1,19 @@ +var _switch = /*#__PURE__*/ new WeakSet(), _bar = /*#__PURE__*/ new WeakSet(); +class TestCls { + foo() { + _class_private_method_get(this, _bar, bar).call(this); + _class_private_method_get(this, _switch, __switch).call(this); + } + constructor(){ + _class_private_method_init(this, _switch); + _class_private_method_init(this, _bar); + } +} +function __switch() { + console.log("#switch called"); +} +function bar() { + console.log("#bar called"); +} +let a = new TestCls(); +a.foo(); diff --git a/crates/swc_ecma_transforms_compat/tests/es2022_class_properties.rs b/crates/swc_ecma_transforms_compat/tests/es2022_class_properties.rs index aa0f9ff31e4f..5ceb869d1f48 100644 --- a/crates/swc_ecma_transforms_compat/tests/es2022_class_properties.rs +++ b/crates/swc_ecma_transforms_compat/tests/es2022_class_properties.rs @@ -4831,6 +4831,46 @@ class Cl { "# ); +test!( + syntax(), + |t| { + let unresolved_mark = Mark::new(); + let top_level_mark = Mark::new(); + + chain!( + resolver(unresolved_mark, top_level_mark, false), + class_properties( + Some(t.comments.clone()), + class_properties::Config { + private_as_properties: true, + ..Default::default() + }, + unresolved_mark, + ) + ) + }, + loose_keyword_method, + r##" +class TestCls{ + foo(){ + this.#bar() + this.#switch() + } + #switch(){ + console.log("#switch called") + } + + #bar(){ + console.log("#bar called") + } +} +export {TestCls} + +let a = new TestCls +a.foo() +"## +); + #[testing::fixture("tests/classes/**/exec.js")] fn exec(input: PathBuf) { let src = read_to_string(input).unwrap();