diff --git a/.swcrc.test b/.swcrc.test new file mode 100644 index 000000000000..62585fe7458d --- /dev/null +++ b/.swcrc.test @@ -0,0 +1,12 @@ +{ + "jsc": { + "parser": { + "syntax": "ecmascript", + "decorators": true, + "auto_accessors": true + }, + "transform": { + "decoratorVersion": "2023-11" + } + } +} \ No newline at end of file diff --git a/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2311.js b/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2311.js new file mode 100644 index 000000000000..3a4db96cb4a1 --- /dev/null +++ b/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2311.js @@ -0,0 +1,239 @@ + +var PROP_KIND; +function _apply_decs_2311(targetClass, classDecs, memberDecs, classDecsHaveThis, instanceBrand, parentClass) { + var symbolMetadata = Symbol.metadata || Symbol.for("Symbol.metadata"); + var defineProperty = Object.defineProperty; + var create = Object.create; + var metadata; + var existingNonFields = [ + create(null), + create(null) + ]; + var hasClassDecs = classDecs.length; + var _; + function createRunInitializers(initializers, useStaticThis, hasValue) { + return function (thisArg, value) { + if (useStaticThis) { + value = thisArg; + thisArg = targetClass; + } + for (var i = 0; i < initializers.length; i++) { + value = initializers[i].apply(thisArg, hasValue ? [ + value + ] : []); + } + return hasValue ? value : thisArg; + }; + } + function assertCallable(fn, hint1, hint2, throwUndefined) { + if (typeof fn !== "function") { + if (throwUndefined || fn !== void 0) { + throw new TypeError(hint1 + " must " + (hint2 || "be") + " a function" + (throwUndefined ? "" : " or undefined")); + } + } + return fn; + } + function applyDec(Class, decInfo, decoratorsHaveThis, name, kind, initializers, ret, isStatic, isPrivate, isField, hasPrivateBrand) { + function assertInstanceIfPrivate(target) { + if (!hasPrivateBrand(target)) { + throw new TypeError("Attempted to access private element on non-instance"); + } + } + var decs = [].concat(decInfo[0]), decVal = decInfo[3], isClass = !ret; + var isAccessor = kind === 1; + var isGetter = kind === 3; + var isSetter = kind === 4; + var isMethod = kind === 2; + function _bindPropCall(name, useStaticThis, before) { + return function (_this, value) { + if (useStaticThis) { + value = _this; + _this = Class; + } + if (before) { + before(_this); + } + return desc[name].call(_this, value); + }; + } + if (!isClass) { + var desc = {}, init = [], key = isGetter ? "get" : isSetter || isAccessor ? "set" : "value"; + if (isPrivate) { + if (isField || isAccessor) { + desc = { + get: _set_function_name(function () { + return decVal(this); + }, name, "get"), + set: function (value) { + decInfo[4](this, value); + } + }; + } else { + desc[key] = decVal; + } + if (!isField) { + _set_function_name(desc[key], name, isMethod ? "" : key); + } + } else if (!isField) { + desc = Object.getOwnPropertyDescriptor(Class, name); + } + if (!isField && !isPrivate) { + _ = existingNonFields[+isStatic][name]; + if (_ && (_ ^ kind) !== 7) { + throw new Error("Decorating two elements with the same name (" + desc[key].name + ") is not supported yet"); + } + existingNonFields[+isStatic][name] = kind < 3 ? 1 : kind; + } + } + var newValue = Class; + for (var i = decs.length - 1; i >= 0; i -= decoratorsHaveThis ? 2 : 1) { + var dec = assertCallable(decs[i], "A decorator", "be", true), decThis = decoratorsHaveThis ? decs[i - 1] : void 0; + var decoratorFinishedRef = {}; + var ctx = { + kind: [ + "field", + "accessor", + "method", + "getter", + "setter", + "class" + ][kind], + name: name, + metadata: metadata, + addInitializer: (function (decoratorFinishedRef, initializer) { + if (decoratorFinishedRef.v) { + throw new TypeError("attempted to call addInitializer after decoration was finished"); + } + assertCallable(initializer, "An initializer", "be", true); + initializers.push(initializer); + }).bind(null, decoratorFinishedRef) + }; + if (isClass) { + _ = dec.call(decThis, newValue, ctx); + decoratorFinishedRef.v = 1; + if (assertCallable(_, "class decorators", "return")) { + newValue = _; + } + } else { + ctx.static = isStatic; + ctx.private = isPrivate; + _ = ctx.access = { + has: isPrivate ? hasPrivateBrand.bind() : function (target) { + return name in target; + } + }; + if (!isSetter) { + _.get = isPrivate ? isMethod ? function (_this) { + assertInstanceIfPrivate(_this); + return desc.value; + } : _bindPropCall("get", 0, assertInstanceIfPrivate) : function (target) { + return target[name]; + }; + } + if (!isMethod && !isGetter) { + _.set = isPrivate ? _bindPropCall("set", 0, assertInstanceIfPrivate) : function (target, v) { + target[name] = v; + }; + } + newValue = dec.call(decThis, isAccessor ? { + get: desc.get, + set: desc.set + } : desc[key], ctx); + decoratorFinishedRef.v = 1; + if (isAccessor) { + if (typeof newValue === "object" && newValue) { + if (_ = assertCallable(newValue.get, "accessor.get")) { + desc.get = _; + } + if (_ = assertCallable(newValue.set, "accessor.set")) { + desc.set = _; + } + if (_ = assertCallable(newValue.init, "accessor.init")) { + init.unshift(_); + } + } else if (newValue !== void 0) { + throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); + } + } else if (assertCallable(newValue, (isField ? "field" : "method") + " decorators", "return")) { + if (isField) { + init.unshift(newValue); + } else { + desc[key] = newValue; + } + } + } + } + if (kind < 2) { + ret.push(createRunInitializers(init, isStatic, 1), createRunInitializers(initializers, isStatic, 0)); + } + if (!isField && !isClass) { + if (isPrivate) { + if (isAccessor) { + ret.splice(-1, 0, _bindPropCall("get", isStatic), _bindPropCall("set", isStatic)); + } else { + ret.push(isMethod ? desc[key] : assertCallable.call.bind(desc[key])); + } + } else { + defineProperty(Class, name, desc); + } + } + return newValue; + } + function applyMemberDecs() { + var ret = []; + var protoInitializers; + var staticInitializers; + var pushInitializers = function (initializers) { + if (initializers) { + ret.push(createRunInitializers(initializers)); + } + }; + var applyMemberDecsOfKind = function (isStatic, isField) { + for (var i = 0; i < memberDecs.length; i++) { + var decInfo = memberDecs[i]; + var kind = decInfo[1]; + var kindOnly = kind & 7; + if ((kind & 8) == isStatic && !kindOnly == isField) { + var name = decInfo[2]; + var isPrivate = !!decInfo[3]; + var decoratorsHaveThis = kind & 16; + applyDec(isStatic ? targetClass : targetClass.prototype, decInfo, decoratorsHaveThis, isPrivate ? "#" + name : _to_property_key(name), kindOnly, kindOnly < 2 ? [] : isStatic ? staticInitializers = staticInitializers || [] : protoInitializers = protoInitializers || [], ret, !!isStatic, isPrivate, isField, isStatic && isPrivate ? function (_) { + return _check_in_rhs(_) === targetClass; + } : instanceBrand); + } + } + }; + applyMemberDecsOfKind(8, 0); + applyMemberDecsOfKind(0, 0); + applyMemberDecsOfKind(8, 1); + applyMemberDecsOfKind(0, 1); + pushInitializers(protoInitializers); + pushInitializers(staticInitializers); + return ret; + } + function defineMetadata(Class) { + return defineProperty(Class, symbolMetadata, { + configurable: true, + enumerable: true, + value: metadata + }); + } + if (parentClass !== undefined) { + metadata = parentClass[symbolMetadata]; + } + metadata = create(metadata == null ? null : metadata); + _ = applyMemberDecs(); + if (!hasClassDecs) defineMetadata(targetClass); + return { + e: _, + get c() { + var initializers = []; + return hasClassDecs && [ + defineMetadata(targetClass = applyDec(targetClass, [ + classDecs + ], classDecsHaveThis, targetClass.name, 5, initializers)), + createRunInitializers(initializers, 1) + ]; + } + }; +} diff --git a/crates/swc_ecma_transforms_base/src/helpers/_check_in_rhs.js b/crates/swc_ecma_transforms_base/src/helpers/_check_in_rhs.js new file mode 100644 index 000000000000..ce7797db5047 --- /dev/null +++ b/crates/swc_ecma_transforms_base/src/helpers/_check_in_rhs.js @@ -0,0 +1,6 @@ +function _check_in_rhs(value) { + if (Object(value) !== value) { + throw TypeError("right-hand side of 'in' should be an object, got " + (value !== null ? typeof value : "null")); + } + return value; +} diff --git a/crates/swc_ecma_transforms_base/src/helpers/_set_function_name.js b/crates/swc_ecma_transforms_base/src/helpers/_set_function_name.js new file mode 100644 index 000000000000..05b112c3a623 --- /dev/null +++ b/crates/swc_ecma_transforms_base/src/helpers/_set_function_name.js @@ -0,0 +1,13 @@ +function _set_function_name(fn, name, prefix) { + if (typeof name === "symbol") { + name = name.description; + name = name ? "[" + name + "]" : ""; + } + try { + Object.defineProperty(fn, "name", { + configurable: true, + value: prefix ? prefix + " " + name : name + }); + } catch (_) { } + return fn; +} diff --git a/crates/swc_ecma_transforms_base/src/helpers/mod.rs b/crates/swc_ecma_transforms_base/src/helpers/mod.rs index 959554fcb326..22c90a541816 100644 --- a/crates/swc_ecma_transforms_base/src/helpers/mod.rs +++ b/crates/swc_ecma_transforms_base/src/helpers/mod.rs @@ -419,6 +419,10 @@ define_helpers!(Helpers { dispose: (), using: (), using_ctx: (), + + check_in_rhs: (), + set_function_name: (), + apply_decs_2311: (check_in_rhs, set_function_name, to_property_key), }); pub fn inject_helpers(global_mark: Mark) -> impl Pass + VisitMut { diff --git a/crates/swc_ecma_transforms_proposal/src/decorator_2023_11.rs b/crates/swc_ecma_transforms_proposal/src/decorator_2023_11.rs new file mode 100644 index 000000000000..ffb6a4f8bf65 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/src/decorator_2023_11.rs @@ -0,0 +1,7 @@ +use swc_ecma_ast::Pass; + +use crate::{decorator_impl::decorator_impl, DecoratorVersion}; + +pub fn decorator_2023_11() -> impl Pass { + decorator_impl(DecoratorVersion::V202311) +} diff --git a/crates/swc_ecma_transforms_proposal/src/decorator_impl.rs b/crates/swc_ecma_transforms_proposal/src/decorator_impl.rs index ef8339da53fb..ee4296242305 100644 --- a/crates/swc_ecma_transforms_proposal/src/decorator_impl.rs +++ b/crates/swc_ecma_transforms_proposal/src/decorator_impl.rs @@ -1,1925 +1,1893 @@ -use std::{collections::VecDeque, iter::once, mem::take}; - -use rustc_hash::FxHashMap; -use swc_atoms::{atom, Atom}; -use swc_common::{util::take::Take, Mark, Spanned, SyntaxContext, DUMMY_SP}; use swc_ecma_ast::*; -use swc_ecma_transforms_base::{helper, helper_expr}; -use swc_ecma_utils::{ - alias_ident_for, constructor::inject_after_super, default_constructor_with_span, - is_maybe_branch_directive, private_ident, prop_name_to_expr_value, quote_ident, replace_ident, - stack_size::maybe_grow_default, ExprFactory, IdentRenamer, -}; -use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith}; +use swc_ecma_visit::{noop_fold_type, Fold, FoldWith, fold_pass}; +use swc_common::{DUMMY_SP, SyntaxContext}; +use swc_ecma_utils::{quote_ident, ExprFactory}; +use swc_ecma_transforms_base::enable_helper; use crate::DecoratorVersion; -pub(crate) fn decorator_impl(version: DecoratorVersion) -> impl Pass { - visit_mut_pass(DecoratorPass { - version, - ..Default::default() - }) -} - -#[derive(Default)] -struct DecoratorPass { - /// Variables without initializer. - extra_vars: Vec, - - extra_lets: Vec, - - state: ClassState, +// Decorator kind constants matching Babel's implementation +const FIELD: f64 = 0.0; +const ACCESSOR: f64 = 1.0; +const METHOD: f64 = 2.0; +const GETTER: f64 = 3.0; +const SETTER: f64 = 4.0; - /// Prepended before the class - pre_class_inits: Vec>, +const STATIC_OLD_VERSION: f64 = 5.0; // Before 2023-05 +const STATIC: f64 = 8.0; // 1 << 3 +const DECORATORS_HAVE_THIS: f64 = 16.0; // 1 << 4 - rename_map: FxHashMap, - - extra_exports: Vec, - - #[allow(unused)] - version: DecoratorVersion, +pub(crate) fn decorator_impl(version: DecoratorVersion) -> impl Pass { + fold_pass(DecoratorTransform { version }) } -#[derive(Default)] -struct ClassState { - private_id_index: u32, - - static_lhs: Vec, - proto_lhs: Vec, - - /// If not empty, `initProto` should be injected to the constructor. - init_proto: Option, - init_proto_args: Vec>, - - init_static: Option, - init_static_args: Vec>, - - /// Injected into static blocks. - extra_stmts: Vec, - - class_lhs: Vec>, - class_decorators: Vec>, - - super_class: Option, +struct DecoratorTransform { + version: DecoratorVersion, } -impl DecoratorPass { - fn preserve_side_effect_of_decorators( - &mut self, - decorators: Vec, - ) -> Vec> { - decorators - .into_iter() - .map(|e| Some(self.preserve_side_effect_of_decorator(e.expr).as_arg())) - .collect() - } - - fn preserve_side_effect_of_decorator(&mut self, dec: Box) -> Box { - if dec.is_ident() || dec.is_arrow() || dec.is_fn_expr() { - return dec; - } - - let ident = private_ident!("_dec"); - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: ident.clone().into(), - init: None, - definite: false, - }); - self.pre_class_inits.push( - AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: ident.clone().into(), - right: dec, - } - .into(), - ); - - ident.into() - } - - /// Moves `cur_inits` to `extra_stmts`. - fn consume_inits(&mut self) { - if self.state.init_proto_args.is_empty() - && self.state.init_static_args.is_empty() - && self.state.init_proto.is_none() - && self.state.init_static.is_none() - && self.state.class_decorators.is_empty() - { - return; - } - - let mut e_lhs = Vec::new(); - let mut combined_args = vec![ThisExpr { span: DUMMY_SP }.as_arg()]; - - for id in self - .state - .static_lhs - .drain(..) - .chain(self.state.proto_lhs.drain(..)) - { - e_lhs.push(Some(id.into())); - } - - if let Some(init) = self.state.init_proto.clone() { - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: init.clone().into(), - init: None, - definite: false, - }); - - e_lhs.push(Some(init.into())); - } - - if let Some(init) = self.state.init_static.clone() { - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: init.clone().into(), - init: None, - definite: false, - }); - - e_lhs.push(Some(init.into())); - } - - combined_args.push( - ArrayLit { - span: DUMMY_SP, - elems: self - .state - .init_static_args - .drain(..) - .chain(self.state.init_proto_args.drain(..)) - .collect(), - } - .as_arg(), - ); - - combined_args.push( - ArrayLit { - span: DUMMY_SP, - elems: self.state.class_decorators.take(), - } - .as_arg(), - ); - - if let Some(super_class) = self.state.super_class.as_ref() { - combined_args.push(super_class.clone().as_arg()); - } - - let e_pat = if e_lhs.is_empty() { - None - } else { - Some(ObjectPatProp::KeyValue(KeyValuePatProp { - key: PropName::Ident(atom!("e").into()), - value: ArrayPat { - span: DUMMY_SP, - elems: e_lhs, - type_ann: Default::default(), - optional: false, - } - .into(), - })) - }; - - let c_pat = if self.state.class_lhs.is_empty() { - None - } else { - Some(ObjectPatProp::KeyValue(KeyValuePatProp { - key: PropName::Ident(atom!("c").into()), - value: ArrayPat { - span: DUMMY_SP, - elems: self.state.class_lhs.take(), - type_ann: Default::default(), - optional: false, - } - .into(), - })) - }; - - let expr = AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: ObjectPat { - span: DUMMY_SP, - props: e_pat.into_iter().chain(c_pat).collect(), - optional: false, - type_ann: None, - } - .into(), - right: Box::new( - CallExpr { - span: DUMMY_SP, - callee: helper!(apply_decs_2203_r), - args: combined_args, - ..Default::default() - } - .into(), - ), +impl DecoratorTransform { + fn transform_class_with_decorators(&mut self, mut class: Class) -> (Class, Vec) { + let mut has_decorators = !class.decorators.is_empty(); + let mut element_decs = Vec::new(); + let mut class_decs = Vec::new(); + let mut init_vars = Vec::new(); + let mut extra_stmts = Vec::new(); + let mut new_members = Vec::new(); + let mut field_initializer_expressions: Vec = vec![]; + let mut static_field_initializer_expressions: Vec = vec![]; + let mut accessor_counter = 0; + let mut proto_init_local: Option = None; + let mut static_init_local: Option = None; + + // Process class decorators + for decorator in &class.decorators { + class_decs.push(decorator.expr.clone()); } - .into(); - - self.state.extra_stmts.push( - ExprStmt { - span: DUMMY_SP, - expr, - } - .into(), - ); - if let Some(init) = self.state.init_static.take() { - self.state.extra_stmts.push( - ExprStmt { - span: DUMMY_SP, - expr: CallExpr { - span: DUMMY_SP, - callee: init.as_callee(), - args: vec![ThisExpr { span: DUMMY_SP }.as_arg()], - ..Default::default() - } - .into(), - } - .into(), + // Collect and sort members first according to Babel's ordering + let mut members_to_process: Vec<(ClassMember, usize)> = class.body.into_iter().enumerate().map(|(idx, member)| (member, idx)).collect(); + + // Sort according to Babel's decorator application order: + // 1. static non-fields (accessors, methods, getters, setters) + // 2. instance non-fields (accessors, methods, getters, setters) + // 3. static fields + // 4. instance fields + members_to_process.sort_by_key(|(member, original_idx)| { + let is_static = match member { + ClassMember::Method(m) => m.is_static, + ClassMember::PrivateMethod(m) => m.is_static, + ClassMember::ClassProp(p) => p.is_static, + ClassMember::PrivateProp(p) => p.is_static, + ClassMember::AutoAccessor(a) => a.is_static, + _ => false, + }; + + let is_field = matches!(member, + ClassMember::ClassProp(_) | + ClassMember::PrivateProp(_) ); - } - } - - /// Returns (name, initilaizer_name) - fn initializer_name(&mut self, name: &mut PropName, prefix: &str) -> (Box, Ident) { - match name { - PropName::Ident(i) => ( - Lit::Str(Str { - span: i.span, - value: i.sym.clone(), - raw: None, - }) - .into(), - Ident::new( - format!("_{prefix}_{}", i.sym).into(), - i.span, - SyntaxContext::empty().apply_mark(Mark::new()), - ), - ), - PropName::Computed(c) if c.expr.is_ident() => match &*c.expr { - Expr::Ident(i) => ( - i.clone().into(), - Ident::new( - format!("_{prefix}_{}", i.sym).into(), - i.span, - SyntaxContext::empty().apply_mark(Mark::new()), - ), - ), - _ => { - unreachable!() - } - }, - _ => { - let key_ident = private_ident!(name.span(), "_computedKey"); - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: key_ident.clone().into(), - init: None, - definite: false, - }); - - self.pre_class_inits.push( - AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: key_ident.clone().into(), - right: Box::new(prop_name_to_expr_value(name.take())), - } - .into(), - ); - *name = PropName::Computed(ComputedPropName { - span: DUMMY_SP, - expr: key_ident.clone().into(), - }); - - let init = Ident::new( - format!("_{prefix}_computedKey").into(), - key_ident.span, - SyntaxContext::empty().apply_mark(Mark::new()), - ); - - (key_ident.into(), init) - } - } - } - - fn ensure_constructor<'a>(&mut self, c: &'a mut Class) -> &'a mut Constructor { - let mut insert_index = 0; - for (i, member) in c.body.iter().enumerate() { - if let ClassMember::Constructor(constructor) = member { - // decorators occur before typescript's type strip, so skip ctor overloads - if constructor.body.is_some() { - if let Some(ClassMember::Constructor(c)) = c.body.get_mut(i) { - return c; - } else { - unreachable!() - } - } else { - insert_index = i + 1; - } + + let has_decorators = match member { + ClassMember::Method(m) => !m.function.decorators.is_empty(), + ClassMember::PrivateMethod(m) => !m.function.decorators.is_empty(), + ClassMember::ClassProp(p) => !p.decorators.is_empty(), + ClassMember::PrivateProp(p) => !p.decorators.is_empty(), + ClassMember::AutoAccessor(a) => !a.decorators.is_empty(), + _ => false, + }; + + if !has_decorators { + return (4, *original_idx); // Non-decorated members keep original order } - } - - c.body.insert( - insert_index, - default_constructor_with_span(c.super_class.is_some(), c.span).into(), - ); - - if let Some(ClassMember::Constructor(c)) = c.body.get_mut(insert_index) { - c - } else { - unreachable!() - } - } - - fn ensure_identity_constructor<'a>(&mut self, c: &'a mut Class) -> &'a mut Constructor { - let mut insert_index = 0; - for (i, member) in c.body.iter().enumerate() { - if let ClassMember::Constructor(constructor) = member { - // decorators occur before typescript's type strip, so skip ctor overloads - if constructor.body.is_some() { - if let Some(ClassMember::Constructor(c)) = c.body.get_mut(i) { - return c; - } else { - unreachable!() - } - } else { - insert_index = i + 1; - } + + match (is_static, is_field) { + (true, false) => (0, *original_idx), // static non-fields + (false, false) => (1, *original_idx), // instance non-fields + (true, true) => (2, *original_idx), // static fields + (false, true) => (3, *original_idx), // instance fields } - } - - c.body.insert( - insert_index, - ClassMember::Constructor(Constructor { - span: DUMMY_SP, - key: PropName::Ident(atom!("constructor").into()), - params: Vec::new(), - body: Some(BlockStmt { - span: DUMMY_SP, - stmts: Vec::new(), - ..Default::default() - }), - ..Default::default() - }), - ); - - if let Some(ClassMember::Constructor(c)) = c.body.get_mut(insert_index) { - c - } else { - unreachable!() - } - } - - fn handle_super_class(&mut self, class: &mut Class) { - if let Some(super_class) = class.super_class.take() { - let id = alias_ident_for(&super_class, "_super"); - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: id.clone().into(), - init: None, - definite: false, - }); - - class.super_class = Some( - AssignExpr { - span: DUMMY_SP, - op: AssignOp::Assign, - left: id.clone().into(), - right: super_class, - } - .into(), - ); - - self.state.super_class = Some(id); - } - } - - fn handle_class_expr(&mut self, class: &mut Class, ident: Option<&Ident>) -> Ident { - debug_assert!( - !class.decorators.is_empty(), - "handle_class_decorator should be called only when decorators are present" - ); - - let init_class = private_ident!("_initClass"); - - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: init_class.clone().into(), - init: None, - definite: false, - }); - - let new_class_name = ident.as_ref().map_or_else( - || private_ident!("_class"), - |i| private_ident!(format!("_{}", i.sym)), - ); - - if let Some(ident) = ident { - replace_ident(&mut class.body, ident.to_id(), &new_class_name); - } - - self.state - .class_lhs - .push(Some(new_class_name.clone().into())); - self.state.class_lhs.push(Some(init_class.clone().into())); - - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: new_class_name.clone().into(), - init: None, - definite: false, }); - let decorators = self.preserve_side_effect_of_decorators(class.decorators.take()); - self.state.class_decorators.extend(decorators); - self.handle_super_class(class); - - { - let call_stmt = CallExpr { - span: DUMMY_SP, - callee: init_class.as_callee(), - args: Vec::new(), - ..Default::default() - } - .into_stmt(); - - class.body.push(ClassMember::StaticBlock(StaticBlock { - span: DUMMY_SP, - body: BlockStmt { - span: DUMMY_SP, - stmts: vec![call_stmt], - ..Default::default() - }, - })); - } - - new_class_name - } - - // This function will call `visit` internally. - fn handle_class_decl(&mut self, c: &mut ClassDecl) -> Stmt { - let old_state = take(&mut self.state); - - let decorators = self.preserve_side_effect_of_decorators(c.class.decorators.take()); - - let init_class = private_ident!("_initClass"); - - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: init_class.clone().into(), - init: None, - definite: false, - }); - - let preserved_class_name = c.ident.clone().into_private(); - let new_class_name = private_ident!(format!("_{}", c.ident.sym)); - - self.extra_lets.push(VarDeclarator { - span: DUMMY_SP, - name: new_class_name.clone().into(), - init: None, - definite: false, - }); - - self.rename_map - .insert(c.ident.to_id(), new_class_name.to_id()); - - self.state - .class_lhs - .push(Some(new_class_name.clone().into())); - self.state.class_lhs.push(Some(init_class.clone().into())); - - self.state.class_decorators.extend(decorators); - self.handle_super_class(&mut c.class); - - let mut body = c.class.body.take(); - - let has_static_member = body.iter().any(|m| match m { - ClassMember::Method(m) => m.is_static, - ClassMember::PrivateMethod(m) => m.is_static, - ClassMember::AutoAccessor(m) => m.is_static, - ClassMember::ClassProp(ClassProp { is_static, .. }) - | ClassMember::PrivateProp(PrivateProp { is_static, .. }) => *is_static, - ClassMember::StaticBlock(_) => true, - _ => false, - }); - - if has_static_member { - let mut last_static_block = None; - - self.process_decorators_of_class_members(&mut body); - - // Move static blocks into property initializers - for m in body.iter_mut() { - match m { - ClassMember::ClassProp(ClassProp { value, .. }) - | ClassMember::PrivateProp(PrivateProp { value, .. }) => { - if let Some(value) = value { - if let Some(last_static_block) = last_static_block.take() { - **value = SeqExpr { - span: DUMMY_SP, - exprs: vec![ - Box::new(Expr::Call(CallExpr { - span: DUMMY_SP, - callee: ArrowExpr { - span: DUMMY_SP, - params: Vec::new(), - body: Box::new(BlockStmtOrExpr::BlockStmt( - BlockStmt { - span: DUMMY_SP, - stmts: last_static_block, - ..Default::default() - }, - )), - is_async: false, - is_generator: false, - ..Default::default() - } - .as_callee(), - args: Vec::new(), - ..Default::default() - })), - value.take(), - ], - } - .into() - } - } - } - ClassMember::StaticBlock(s) => match &mut last_static_block { - None => { - last_static_block = Some(s.body.stmts.take()); - } - Some(v) => { - v.append(&mut s.body.stmts); - } - }, - _ => {} - } - } - - // Drop static blocks - body.retain(|m| !matches!(m, ClassMember::StaticBlock(..) | ClassMember::Empty(..))); - - for m in body.iter_mut() { - match m { - ClassMember::ClassProp(..) - | ClassMember::PrivateProp(..) - | ClassMember::AutoAccessor(..) => { - replace_ident(m, c.ident.to_id(), &new_class_name); - } - - _ => {} - } - } - - let mut inner_class = ClassDecl { - ident: c.ident.clone(), - declare: Default::default(), - class: Box::new(Class { - span: DUMMY_SP, - decorators: Vec::new(), - body, - super_class: c.class.super_class.take(), - ..Default::default() - }), - }; - - inner_class.class.visit_mut_with(self); + // Process class members in sorted order + for (member, _) in members_to_process { + match member { + ClassMember::ClassProp(mut prop) if !prop.decorators.is_empty() => { + has_decorators = true; + + let key_name = match &prop.key { + PropName::Ident(id) => id.sym.to_string(), + PropName::Str(s) => s.value.to_string(), + PropName::Computed(_) => "computedKey".to_string(), + _ => "field".to_string(), + }; - for m in inner_class.class.body.iter_mut() { - let mut should_move = false; + let init_var = format!("_init_{}", key_name); + let init_id = Ident::new(init_var.as_str().into(), DUMMY_SP, Default::default()); + init_vars.push(init_id.clone()); - match m { - ClassMember::PrivateProp(p) => { - if p.is_static { - should_move = true; - p.is_static = false; - } - } - ClassMember::PrivateMethod(p) => { - if p.is_static { - should_move = true; - p.is_static = false; + // Create element descriptor [decorator(s), kind, name] + let kind_value = if prop.is_static { + if static_init_local.is_none() { + static_init_local = Some(Ident::new("_initStatic".into(), DUMMY_SP, Default::default())); } - } - - ClassMember::AutoAccessor(p) => { - if p.is_static { - should_move = true; - p.is_static = false; + match self.version { + DecoratorVersion::V202311 => STATIC + FIELD, + _ => STATIC_OLD_VERSION } - } - _ => (), - } - - if should_move { - c.class.body.push(m.take()) - } - } - - c.class.body.insert( - 0, - ClassMember::StaticBlock(StaticBlock { - span: DUMMY_SP, - body: BlockStmt { - span: DUMMY_SP, - stmts: vec![Stmt::Decl(Decl::Class(inner_class))], - ..Default::default() - }, - }), - ); - - replace_ident(&mut c.class, c.ident.to_id(), &preserved_class_name); - - { - let constructor = self.ensure_identity_constructor(&mut c.class); - - let super_call = CallExpr { - span: DUMMY_SP, - callee: Callee::Super(Super { span: DUMMY_SP }), - args: vec![c.ident.clone().as_arg()], - ..Default::default() - } - .into(); - let static_call = last_static_block.map(|last| { - CallExpr { - span: DUMMY_SP, - callee: ArrowExpr { - span: DUMMY_SP, - params: Vec::new(), - body: Box::new(BlockStmtOrExpr::BlockStmt(BlockStmt { - span: DUMMY_SP, - stmts: last, - ..Default::default() - })), - is_async: false, - is_generator: false, - ..Default::default() - } - .as_callee(), - args: Vec::new(), - ..Default::default() - } - .into() - }); - - let init_class_call = CallExpr { - span: DUMMY_SP, - callee: init_class.as_callee(), - args: Vec::new(), - ..Default::default() - } - .into(); - - constructor.body.as_mut().unwrap().stmts.insert( - 0, - SeqExpr { - span: DUMMY_SP, - exprs: once(super_call) - .chain(static_call) - .chain(once(init_class_call)) - .collect(), - } - .into_stmt(), - ); - } - - let class = Box::new(Class { - span: DUMMY_SP, - decorators: Vec::new(), - body: c.class.body.take(), - super_class: Some(Box::new(helper_expr!(identity))), - ..Default::default() - }); - - self.state = old_state; - - return NewExpr { - span: DUMMY_SP, - callee: ClassExpr { ident: None, class }.into(), - args: Some(Vec::new()), - ..Default::default() - } - .into_stmt(); - } - for m in body.iter_mut() { - if let ClassMember::Constructor(..) = m { - c.class.body.push(m.take()); - } - } - body.visit_mut_with(self); - c.ident = preserved_class_name.clone(); - replace_ident(&mut c.class, c.ident.to_id(), &preserved_class_name); - c.class.body.extend(body); - c.visit_mut_with(self); - c.class.body.push(ClassMember::StaticBlock(StaticBlock { - span: DUMMY_SP, - body: BlockStmt { - span: DUMMY_SP, - stmts: vec![CallExpr { - span: DUMMY_SP, - callee: init_class.as_callee(), - args: Vec::new(), - ..Default::default() - } - .into_stmt()], - ..Default::default() - }, - })); - self.state = old_state; - - c.take().into() - } - - fn process_decorators(&mut self, decorators: &mut [Decorator]) { - decorators.iter_mut().for_each(|dec| { - let e = self.preserve_side_effect_of_decorator(dec.expr.take()); - - dec.expr = e; - }) - } - - fn process_prop_name(&mut self, name: &mut PropName) { - match name { - PropName::Ident(..) => {} - PropName::Computed(c) if c.expr.is_ident() => {} - _ => { - let ident = private_ident!("_computedKey"); - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: ident.clone().into(), - init: None, - definite: false, - }); - - self.pre_class_inits.push( - AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: ident.clone().into(), - right: Box::new(prop_name_to_expr_value(name.take())), - } - .into(), - ); - *name = PropName::Computed(ComputedPropName { - span: DUMMY_SP, - expr: ident.into(), - }); - } - } - } - - fn process_decorators_of_class_members(&mut self, members: &mut [ClassMember]) { - for mut m in members { - match &mut m { - ClassMember::Method(m) if m.function.body.is_some() => { - self.process_decorators(&mut m.function.decorators); - self.process_prop_name(&mut m.key); - } - ClassMember::PrivateMethod(m) if m.function.body.is_some() => { - self.process_decorators(&mut m.function.decorators); - } - ClassMember::ClassProp(m) if !m.declare => { - self.process_decorators(&mut m.decorators); - self.process_prop_name(&mut m.key); - } - ClassMember::PrivateProp(m) => { - self.process_decorators(&mut m.decorators); - } - ClassMember::AutoAccessor(m) => { - self.process_decorators(&mut m.decorators); - } - - _ => {} - } - } - } -} - -impl VisitMut for DecoratorPass { - noop_visit_mut_type!(); - - fn visit_mut_class(&mut self, n: &mut Class) { - let old_stmts = self.state.extra_stmts.take(); - - n.visit_mut_children_with(self); - - if let Some(init_proto) = self.state.init_proto.clone() { - let init_proto_expr = CallExpr { - span: DUMMY_SP, - callee: init_proto.clone().as_callee(), - args: vec![ThisExpr { span: DUMMY_SP }.as_arg()], - ..Default::default() - }; - let mut proto_inited = false; - for member in n.body.iter_mut() { - if let ClassMember::ClassProp(prop) = member { - if prop.is_static { - continue; - } - if let Some(value) = prop.value.clone() { - prop.value = Some(Expr::from_exprs(vec![ - init_proto_expr.clone().into(), - value, - ])); - - proto_inited = true; - break; - } - } else if let ClassMember::PrivateProp(prop) = member { - if prop.is_static { - continue; - } - if let Some(value) = prop.value.clone() { - prop.value = Some(Expr::from_exprs(vec![ - init_proto_expr.clone().into(), - value, - ])); - - proto_inited = true; - break; - } - } - } - - if !proto_inited { - let c = self.ensure_constructor(n); - - inject_after_super(c, vec![Box::new(init_proto_expr.into())]) - } - } - - self.consume_inits(); - - if !self.state.extra_stmts.is_empty() { - n.body.insert( - 0, - ClassMember::StaticBlock(StaticBlock { - span: DUMMY_SP, - body: BlockStmt { - span: DUMMY_SP, - stmts: self.state.extra_stmts.take(), - ..Default::default() - }, - }), - ); - } - - self.state.init_proto = None; - - self.state.extra_stmts = old_stmts; - } - - fn visit_mut_class_member(&mut self, n: &mut ClassMember) { - n.visit_mut_children_with(self); - - if let ClassMember::PrivateMethod(p) = n { - if p.function.decorators.is_empty() { - return; - } - - let decorators = self.preserve_side_effect_of_decorators(p.function.decorators.take()); - let dec = merge_decorators(decorators); - - let init = private_ident!(format!("_call_{}", p.key.name)); - - self.extra_vars.push(VarDeclarator { - span: p.span, - name: init.clone().into(), - init: None, - definite: false, - }); - - if p.is_static { - self.state - .init_static - .get_or_insert_with(|| private_ident!("_initStatic")); - } else { - self.state - .init_proto - .get_or_insert_with(|| private_ident!("_initProto")); - } - - let caller = FnExpr { - ident: None, - function: p.function.clone(), - }; - - let arg = Some( - ArrayLit { - span: DUMMY_SP, - elems: vec![ - dec, - Some( - if p.is_static { - match p.kind { - MethodKind::Method => 7, - MethodKind::Setter => 9, - MethodKind::Getter => 8, - } - } else { - match p.kind { - MethodKind::Method => 2, - MethodKind::Setter => 4, - MethodKind::Getter => 3, - } - } - .as_arg(), - ), - Some(p.key.name.clone().as_arg()), - Some(caller.as_arg()), - ], - } - .as_arg(), - ); - if p.is_static { - self.state.init_static_args.push(arg); - } else { - self.state.init_proto_args.push(arg); - } - - if p.is_static { - self.state.static_lhs.push(init.clone()); - } else { - self.state.proto_lhs.push(init.clone()); - } - - match p.kind { - MethodKind::Method => { - let call_stmt = ReturnStmt { - span: DUMMY_SP, - arg: Some(init.into()), - } - .into(); - - p.kind = MethodKind::Getter; - p.function.body = Some(BlockStmt { - span: DUMMY_SP, - stmts: vec![call_stmt], - ..Default::default() - }); - } - MethodKind::Getter => { - let call_stmt = ReturnStmt { - span: DUMMY_SP, - arg: Some( - CallExpr { - span: DUMMY_SP, - callee: init.as_callee(), - args: vec![ThisExpr { span: DUMMY_SP }.as_arg()], - ..Default::default() - } - .into(), - ), - } - .into(); - - p.function.body = Some(BlockStmt { - span: DUMMY_SP, - stmts: vec![call_stmt], - ..Default::default() - }); - } - MethodKind::Setter => { - let call_stmt = ReturnStmt { - span: DUMMY_SP, - arg: Some( - CallExpr { - span: DUMMY_SP, - callee: init.as_callee(), - args: vec![ - ThisExpr { span: DUMMY_SP }.as_arg(), - Ident::from(p.function.params[0].pat.as_ident().unwrap()) - .as_arg(), - ], - ..Default::default() - } - .into(), - ), - } - .into(); - - p.function.body = Some(BlockStmt { - span: DUMMY_SP, - stmts: vec![call_stmt], - ..Default::default() - }); - } - } - } - } - - fn visit_mut_class_members(&mut self, members: &mut Vec) { - let mut new = Vec::with_capacity(members.len()); - - self.process_decorators_of_class_members(members); - - for mut m in members.take() { - match m { - ClassMember::AutoAccessor(mut accessor) => { - accessor.value.visit_mut_with(self); - - let name; - let init; - let field_name_like: Atom; - let private_field = PrivateProp { + } else { + FIELD + }; + + // Handle multiple decorators + let decorator_expr = if prop.decorators.len() == 1 { + prop.decorators[0].expr.clone() + } else { + Box::new(Expr::Array(ArrayLit { + span: DUMMY_SP, + elems: prop.decorators.iter().map(|d| Some(d.expr.clone().as_arg())).collect(), + })) + }; + + let element_desc = ArrayLit { span: DUMMY_SP, - key: match &mut accessor.key { - Key::Private(k) => { - name = Lit::Str(Str { + elems: vec![ + Some(decorator_expr.as_arg()), + Some(Lit::Num(Number { span: DUMMY_SP, value: kind_value, raw: None }).as_arg()), + Some(match &prop.key { + PropName::Ident(id) => Expr::Lit(Lit::Str(Str { span: DUMMY_SP, - value: k.name.clone(), + value: id.sym.clone(), raw: None, - }) - .into(); - init = private_ident!(format!("_init_{}", k.name)); - field_name_like = format!("__{}", k.name).into(); - - self.state.private_id_index += 1; - PrivateName { - span: k.span, - name: format!("__{}_{}", k.name, self.state.private_id_index) - .into(), - } - } - Key::Public(k) => { - (name, init) = self.initializer_name(k, "init"); - field_name_like = format!("__{}", init.sym) - .replacen("init", "private", 1) - .into(); - - self.state.private_id_index += 1; - - PrivateName { - span: init.span, - name: format!( - "{field_name_like}_{}", - self.state.private_id_index - ) - .into(), - } - } - }, - value: if accessor.decorators.is_empty() { - accessor.value - } else { - let init_call = CallExpr { - span: DUMMY_SP, - callee: init.clone().as_callee(), - args: once(ThisExpr { span: DUMMY_SP }.as_arg()) - .chain(accessor.value.take().map(|v| v.as_arg())) - .collect(), - ..Default::default() - } - .into(); - - Some(init_call) - }, - type_ann: None, - is_static: accessor.is_static, - decorators: Default::default(), - accessibility: Default::default(), - is_optional: false, - is_override: false, - readonly: false, - definite: false, - ctxt: Default::default(), + })), + PropName::Str(s) => Expr::Lit(Lit::Str(s.clone())), + PropName::Computed(computed) => *computed.expr.clone(), + _ => Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: "field".into(), + raw: None, + })) + }.as_arg()), + ], }; - - let mut getter_function = Box::new(Function { - params: Default::default(), - decorators: Default::default(), + element_decs.push(element_desc.as_arg()); + + // Transform field to use initializer + prop.decorators.clear(); + let original_value = prop.value.take(); + + let mut init_args = if prop.is_static && self.version != DecoratorVersion::V202311 { + // For static fields in 2022-03, don't pass 'this' + vec![] + } else { + vec![Expr::This(ThisExpr { span: DUMMY_SP }).as_arg()] + }; + if let Some(value) = original_value { + init_args.push((*value).as_arg()); + } + + prop.value = Some(Box::new(Expr::Call(CallExpr { span: DUMMY_SP, - body: Some(BlockStmt { + ctxt: Default::default(), + callee: init_id.as_callee(), + args: init_args, + type_args: None, + }))); + + new_members.push(ClassMember::ClassProp(prop)); + } + ClassMember::PrivateProp(mut prop) if !prop.decorators.is_empty() => { + has_decorators = true; + + let key_name = prop.key.name.to_string(); + let init_var = format!("_init_{}", key_name); + let init_id = Ident::new(init_var.as_str().into(), DUMMY_SP, Default::default()); + init_vars.push(init_id.clone()); + + // Create getter function + let getter_fn = FnExpr { + ident: None, + function: Box::new(Function { + params: vec![], + decorators: vec![], span: DUMMY_SP, - stmts: vec![Stmt::Return(ReturnStmt { + ctxt: Default::default(), + body: Some(BlockStmt { span: DUMMY_SP, - arg: Some(Box::new(Expr::Member(MemberExpr { + ctxt: Default::default(), + stmts: vec![Stmt::Return(ReturnStmt { span: DUMMY_SP, - obj: ThisExpr { span: DUMMY_SP }.into(), - prop: MemberProp::PrivateName(private_field.key.clone()), - }))), - })], - ..Default::default() + arg: Some(Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })), + prop: MemberProp::PrivateName(prop.key.clone()), + }))), + })], + }), + is_generator: false, + is_async: false, + type_params: None, + return_type: None, }), - is_generator: false, - is_async: false, - ..Default::default() - }); - let mut setter_function = { - let param = private_ident!("_v"); + }; - Box::new(Function { + // Create setter function + let setter_fn = FnExpr { + ident: None, + function: Box::new(Function { params: vec![Param { span: DUMMY_SP, - decorators: Default::default(), - pat: param.clone().into(), + decorators: vec![], + pat: Pat::Ident(BindingIdent { + id: Ident::new("value".into(), DUMMY_SP, Default::default()), + type_ann: None, + }), }], - decorators: Default::default(), + decorators: vec![], span: DUMMY_SP, + ctxt: Default::default(), body: Some(BlockStmt { span: DUMMY_SP, + ctxt: Default::default(), stmts: vec![Stmt::Expr(ExprStmt { span: DUMMY_SP, expr: Box::new(Expr::Assign(AssignExpr { span: DUMMY_SP, - op: op!("="), - left: MemberExpr { + op: AssignOp::Assign, + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { span: DUMMY_SP, - obj: ThisExpr { span: DUMMY_SP }.into(), - prop: MemberProp::PrivateName( - private_field.key.clone(), - ), - } - .into(), - right: param.clone().into(), + obj: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })), + prop: MemberProp::PrivateName(prop.key.clone()), + })), + right: Box::new(Expr::Ident(Ident::new("value".into(), DUMMY_SP, Default::default()))), })), })], - ..Default::default() }), is_generator: false, is_async: false, - ..Default::default() - }) + type_params: None, + return_type: None, + }), }; - if !accessor.decorators.is_empty() { - let decorators = - self.preserve_side_effect_of_decorators(accessor.decorators.take()); - let dec = merge_decorators(decorators); + // Create element descriptor [decorator(s), kind, name, getter, setter] + let kind_value = if prop.is_static { + if static_init_local.is_none() { + static_init_local = Some(Ident::new("_initStatic".into(), DUMMY_SP, Default::default())); + } + match self.version { + DecoratorVersion::V202311 => STATIC + FIELD, + _ => STATIC_OLD_VERSION + } + } else { + FIELD + }; + + // Handle multiple decorators + let decorator_expr = if prop.decorators.len() == 1 { + prop.decorators[0].expr.clone() + } else { + Box::new(Expr::Array(ArrayLit { + span: DUMMY_SP, + elems: prop.decorators.iter().map(|d| Some(d.expr.clone().as_arg())).collect(), + })) + }; + + let element_desc = ArrayLit { + span: DUMMY_SP, + elems: vec![ + Some(decorator_expr.as_arg()), + Some(Lit::Num(Number { span: DUMMY_SP, value: kind_value, raw: None }).as_arg()), + Some(Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: prop.key.name.clone(), + raw: None, + })).as_arg()), + Some(Expr::Fn(getter_fn).as_arg()), + Some(Expr::Fn(setter_fn).as_arg()), + ], + }; + element_decs.push(element_desc.as_arg()); + + // Transform field to use initializer + prop.decorators.clear(); + let original_value = prop.value.take(); + + let mut init_args = if prop.is_static && self.version != DecoratorVersion::V202311 { + // For static private fields in 2022-03, don't pass 'this' + vec![] + } else { + vec![Expr::This(ThisExpr { span: DUMMY_SP }).as_arg()] + }; + if let Some(value) = original_value { + init_args.push((*value).as_arg()); + } + + prop.value = Some(Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: init_id.as_callee(), + args: init_args, + type_args: None, + }))); - self.extra_vars.push(VarDeclarator { - span: accessor.span, - name: init.clone().into(), - init: None, - definite: false, - }); + new_members.push(ClassMember::PrivateProp(prop)); + } + ClassMember::AutoAccessor(accessor) if !accessor.decorators.is_empty() => { + has_decorators = true; + accessor_counter += 1; + + let key_name = match &accessor.key { + Key::Public(PropName::Ident(id)) => id.sym.to_string(), + Key::Public(PropName::Str(s)) => s.value.to_string(), + Key::Public(PropName::Computed(_)) => format!("computedKey{}", accessor_counter), + Key::Private(p) => p.name.to_string(), + _ => format!("accessor{}", accessor_counter), + }; - let (getter_var, setter_var) = match &accessor.key { - Key::Private(_) => ( - Some(private_ident!(format!("_get_{}", field_name_like))), - Some(private_ident!(format!("_set_{}", field_name_like))), - ), - Key::Public(_) => Default::default(), - }; + // For auto accessors, we need init, get, set, and init_extra variables in Babel order + // Babel order: [init, get, set, init_extra] due to splice(-1, 0, get, set) + let init_var = format!("_init_{}", key_name); + let init_id = Ident::new(init_var.as_str().into(), DUMMY_SP, Default::default()); + init_vars.push(init_id.clone()); + + let get_var = format!("_get_{}", key_name); + let get_id = Ident::new(get_var.as_str().into(), DUMMY_SP, Default::default()); + init_vars.push(get_id.clone()); + + let set_var = format!("_set_{}", key_name); + let set_id = Ident::new(set_var.as_str().into(), DUMMY_SP, Default::default()); + init_vars.push(set_id.clone()); + + // Only add init_extra for 2023-11 version (comes last) + let init_extra_id = if self.version == DecoratorVersion::V202311 { + let init_extra_var = format!("_init_extra_{}", key_name); + let id = Ident::new(init_extra_var.as_str().into(), DUMMY_SP, Default::default()); + init_vars.push(id.clone()); + Some(id) + } else { + None + }; - let initialize_init = { - ArrayLit { - span: DUMMY_SP, - elems: match &accessor.key { - Key::Private(_) => { - let data = vec![ - dec, - Some(if accessor.is_static { - 6.as_arg() - } else { - 1.as_arg() - }), - Some(name.as_arg()), - Some( - FnExpr { - ident: None, - function: getter_function, - } - .as_arg(), - ), - Some( - FnExpr { - ident: None, - function: setter_function, - } - .as_arg(), - ), - ]; - - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: getter_var.clone().unwrap().into(), - init: None, - definite: false, - }); - self.extra_vars.push(VarDeclarator { - span: DUMMY_SP, - name: setter_var.clone().unwrap().into(), - init: None, - definite: false, - }); + // Create private field name for storage - for private accessors, use a capital letter version + let private_key = match &accessor.key { + Key::Private(p) => PrivateName { + span: p.span, + name: p.name.to_uppercase().into(), + }, + Key::Public(PropName::Ident(ident)) => PrivateName { + span: ident.span, + name: format!("__{}", ident.sym).into(), + }, + _ => PrivateName { + span: accessor.span, + name: format!("__{}", key_name).into(), + } + }; - getter_function = Box::new(Function { - params: Vec::new(), + // Create getter function expression + let getter_expr = if let Key::Private(_) = &accessor.key { + // For private accessors, use version-specific patterns + if accessor.is_static && self.version == DecoratorVersion::V202203 { + // For static private accessors in 2022-03: function() { return this.#A; } + Expr::Fn(FnExpr { + ident: None, + function: Box::new(Function { + params: vec![], + decorators: vec![], + span: DUMMY_SP, + ctxt: Default::default(), + body: Some(BlockStmt { + span: DUMMY_SP, + ctxt: Default::default(), + stmts: vec![Stmt::Return(ReturnStmt { span: DUMMY_SP, - body: Some(BlockStmt { + arg: Some(Box::new(Expr::Member(MemberExpr { span: DUMMY_SP, - stmts: vec![Stmt::Return(ReturnStmt { - span: DUMMY_SP, - arg: Some(Box::new(Expr::Call(CallExpr { - span: DUMMY_SP, - callee: getter_var - .clone() - .unwrap() - .as_callee(), - args: vec![ - ThisExpr { span: DUMMY_SP }.as_arg() - ], - ..Default::default() - }))), - })], - ..Default::default() - }), - is_generator: false, - is_async: false, - ..Default::default() - }); - - let param = private_ident!("_v"); - - setter_function = Box::new(Function { - params: vec![Param { - span: DUMMY_SP, - decorators: Default::default(), - pat: param.clone().into(), - }], - decorators: Default::default(), + obj: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })), + prop: MemberProp::PrivateName(private_key.clone()), + }))), + })], + }), + is_generator: false, + is_async: false, + type_params: None, + return_type: None, + }), + }) + } else { + // For 2023-11 or instance private accessors: o => o.#A + Expr::Arrow(ArrowExpr { + span: DUMMY_SP, + ctxt: Default::default(), + params: vec![Pat::Ident(BindingIdent { + id: Ident::new("o".into(), DUMMY_SP, Default::default()), + type_ann: None, + })], + body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(Ident::new("o".into(), DUMMY_SP, Default::default()))), + prop: MemberProp::PrivateName(private_key.clone()), + })))), + is_async: false, + is_generator: false, + type_params: None, + return_type: None, + }) + } + } else { + // For public accessors, use different patterns for static vs instance + if accessor.is_static { + // For static public accessors: () => TargetClass.#__field + Expr::Arrow(ArrowExpr { + span: DUMMY_SP, + ctxt: Default::default(), + params: vec![], // No parameters for static + body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })), // 'this' refers to the class + prop: MemberProp::PrivateName(private_key.clone()), + })))), + is_async: false, + is_generator: false, + type_params: None, + return_type: None, + }) + } else { + // For instance public accessors: o => o.#__field + Expr::Arrow(ArrowExpr { + span: DUMMY_SP, + ctxt: Default::default(), + params: vec![Pat::Ident(BindingIdent { + id: Ident::new("o".into(), DUMMY_SP, Default::default()), + type_ann: None, + })], + body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(Ident::new("o".into(), DUMMY_SP, Default::default()))), + prop: MemberProp::PrivateName(private_key.clone()), + })))), + is_async: false, + is_generator: false, + type_params: None, + return_type: None, + }) + } + }; + + // Create setter function expression + let setter_expr = if let Key::Private(_) = &accessor.key { + // For private accessors, use version-specific patterns + if accessor.is_static && self.version == DecoratorVersion::V202203 { + // For static private accessors in 2022-03: function(value) { this.#A = value; } + Expr::Fn(FnExpr { + ident: None, + function: Box::new(Function { + params: vec![Param { + span: DUMMY_SP, + decorators: vec![], + pat: Pat::Ident(BindingIdent { + id: Ident::new("value".into(), DUMMY_SP, Default::default()), + type_ann: None, + }), + }], + decorators: vec![], + span: DUMMY_SP, + ctxt: Default::default(), + body: Some(BlockStmt { + span: DUMMY_SP, + ctxt: Default::default(), + stmts: vec![Stmt::Expr(ExprStmt { span: DUMMY_SP, - body: Some(BlockStmt { + expr: Box::new(Expr::Assign(AssignExpr { span: DUMMY_SP, - stmts: vec![Stmt::Expr(ExprStmt { + op: AssignOp::Assign, + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { span: DUMMY_SP, - expr: Box::new(Expr::Call(CallExpr { - span: DUMMY_SP, - callee: setter_var - .clone() - .unwrap() - .as_callee(), - args: vec![ - ThisExpr { span: DUMMY_SP }.as_arg(), - param.as_arg(), - ], - ..Default::default() - })), - })], - ..Default::default() - }), - is_generator: false, - is_async: false, - ..Default::default() - }); - - data - } - Key::Public(_) => { - vec![ - dec, - Some(if accessor.is_static { - 6.as_arg() - } else { - 1.as_arg() - }), - Some(name.as_arg()), - ] - } - }, - } - .as_arg() - }; - - if accessor.is_static { - self.state.static_lhs.push(init); - self.state.init_static_args.push(Some(initialize_init)); - self.state - .static_lhs - .extend(getter_var.into_iter().chain(setter_var)); + obj: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })), + prop: MemberProp::PrivateName(private_key.clone()), + })), + right: Box::new(Expr::Ident(Ident::new("value".into(), DUMMY_SP, Default::default()))), + })), + })], + }), + is_generator: false, + is_async: false, + type_params: None, + return_type: None, + }), + }) } else { - self.state.proto_lhs.push(init); - self.state.init_proto_args.push(Some(initialize_init)); - self.state - .proto_lhs - .extend(getter_var.into_iter().chain(setter_var)); + // For 2023-11 or instance private accessors: (o, v) => o.#A = v + Expr::Arrow(ArrowExpr { + span: DUMMY_SP, + ctxt: Default::default(), + params: vec![ + Pat::Ident(BindingIdent { + id: Ident::new("o".into(), DUMMY_SP, Default::default()), + type_ann: None, + }), + Pat::Ident(BindingIdent { + id: Ident::new("v".into(), DUMMY_SP, Default::default()), + type_ann: None, + }) + ], + body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(Ident::new("o".into(), DUMMY_SP, Default::default()))), + prop: MemberProp::PrivateName(private_key.clone()), + })), + right: Box::new(Expr::Ident(Ident::new("v".into(), DUMMY_SP, Default::default()))), + })))), + is_async: false, + is_generator: false, + type_params: None, + return_type: None, + }) } - + } else { + // For public accessors, use different patterns for static vs instance if accessor.is_static { - self.state - .init_static - .get_or_insert_with(|| private_ident!("_initStatic")); + // For static public accessors: (v) => TargetClass.#__field = v + Expr::Arrow(ArrowExpr { + span: DUMMY_SP, + ctxt: Default::default(), + params: vec![Pat::Ident(BindingIdent { + id: Ident::new("v".into(), DUMMY_SP, Default::default()), + type_ann: None, + })], // Only value parameter for static + body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })), // 'this' refers to the class + prop: MemberProp::PrivateName(private_key.clone()), + })), + right: Box::new(Expr::Ident(Ident::new("v".into(), DUMMY_SP, Default::default()))), + })))), + is_async: false, + is_generator: false, + type_params: None, + return_type: None, + }) } else { - self.state - .init_proto - .get_or_insert_with(|| private_ident!("_initProto")); + // For instance public accessors: (o, v) => o.#__field = v + Expr::Arrow(ArrowExpr { + span: DUMMY_SP, + ctxt: Default::default(), + params: vec![ + Pat::Ident(BindingIdent { + id: Ident::new("o".into(), DUMMY_SP, Default::default()), + type_ann: None, + }), + Pat::Ident(BindingIdent { + id: Ident::new("v".into(), DUMMY_SP, Default::default()), + type_ann: None, + }) + ], + body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(Ident::new("o".into(), DUMMY_SP, Default::default()))), + prop: MemberProp::PrivateName(private_key.clone()), + })), + right: Box::new(Expr::Ident(Ident::new("v".into(), DUMMY_SP, Default::default()))), + })))), + is_async: false, + is_generator: false, + type_params: None, + return_type: None, + }) + } + }; + + // Create element descriptor for all versions + let kind_value = if accessor.is_static { + match self.version { + DecoratorVersion::V202311 => STATIC + ACCESSOR, + _ => STATIC_OLD_VERSION + ACCESSOR } + } else { + ACCESSOR + }; + + // Handle multiple decorators + let decorator_expr = if accessor.decorators.len() == 1 { + accessor.decorators[0].expr.clone() + } else { + Box::new(Expr::Array(ArrayLit { + span: DUMMY_SP, + elems: accessor.decorators.iter().map(|d| Some(d.expr.clone().as_arg())).collect(), + })) + }; + + let mut desc_elems = vec![ + Some(decorator_expr.as_arg()), + Some(Lit::Num(Number { span: DUMMY_SP, value: kind_value, raw: None }).as_arg()), + Some(match &accessor.key { + Key::Public(PropName::Ident(id)) => Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: id.sym.clone(), + raw: None, + })), + Key::Public(PropName::Str(s)) => Expr::Lit(Lit::Str(s.clone())), + Key::Public(PropName::Computed(computed)) => *computed.expr.clone(), + Key::Private(p) => Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: p.name.clone(), + raw: None, + })), + _ => Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: "accessor".into(), + raw: None, + })) + }.as_arg()), + ]; + + // For auto accessors, always add getter and setter functions + desc_elems.push(Some(getter_expr.as_arg())); + desc_elems.push(Some(setter_expr.as_arg())); + + let element_desc = ArrayLit { + span: DUMMY_SP, + elems: desc_elems, + }; + element_decs.push(element_desc.as_arg()); + + // Transform to private field with initializer + let mut init_args = if accessor.is_static && self.version == DecoratorVersion::V202311 { + // For static accessors in 2023-11, don't pass 'this' + vec![] + } else { + // For instance accessors or static in 2022-03, pass 'this' + vec![Expr::This(ThisExpr { span: DUMMY_SP }).as_arg()] + }; + if let Some(value) = accessor.value { + init_args.push((*value).as_arg()); + } else if accessor.is_static && self.version == DecoratorVersion::V202311 { + // For static accessors in 2023-11, always pass 0 as default value + init_args.push(Expr::Lit(Lit::Num(Number { span: DUMMY_SP, value: 0.0, raw: None })).as_arg()); } + + // Static auto accessors don't need _initStatic in 2023-11 + // (they handle initialization through their own init/get/set functions) + + let init_call = Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: init_id.as_callee(), + args: init_args, + type_args: None, + }); + + // Add private field for storage (always use different name from original accessor) + new_members.push(ClassMember::PrivateProp(PrivateProp { + span: accessor.span, + ctxt: Default::default(), + key: private_key.clone(), + value: None, // No initializer - will be set via constructor + type_ann: None, + is_static: accessor.is_static, + decorators: Vec::new(), + accessibility: None, + is_optional: false, + is_override: false, + readonly: false, + definite: false, + })); + + // Get the already created get/set identifiers + let get_id_ref = &get_id; + let set_id_ref = &set_id; match accessor.key { - Key::Private(key) => { - let getter = PrivateMethod { - span: DUMMY_SP, + Key::Public(key) => { + // Add getter + // Create the getter arguments based on version and static status + let getter_args = if accessor.is_static && self.version == DecoratorVersion::V202311 { + // For static accessors in 2023-11, no args + vec![] + } else { + // For instance accessors or static in 2022-03, pass 'this' + vec![Expr::This(ThisExpr { span: accessor.span }).as_arg()] + }; + + new_members.push(ClassMember::Method(ClassMethod { + span: accessor.span, key: key.clone(), - function: getter_function, + function: Box::new(Function { + params: Vec::new(), + decorators: Vec::new(), + span: accessor.span, + ctxt: Default::default(), + body: Some(BlockStmt { + span: accessor.span, + ctxt: Default::default(), + stmts: vec![Stmt::Return(ReturnStmt { + span: accessor.span, + arg: Some(Box::new(Expr::Call(CallExpr { + span: accessor.span, + ctxt: Default::default(), + callee: get_id_ref.clone().as_callee(), + args: getter_args, + type_args: None, + }))), + })], + }), + is_generator: false, + is_async: false, + type_params: None, + return_type: None, + }), kind: MethodKind::Getter, is_static: accessor.is_static, accessibility: None, is_abstract: false, is_optional: false, is_override: false, + })); + + // Add setter + // Create the setter arguments based on version and static status + let setter_args = if accessor.is_static && self.version == DecoratorVersion::V202311 { + // For static accessors in 2023-11, only the value + vec![Expr::Ident(Ident::new("v".into(), accessor.span, Default::default())).as_arg()] + } else { + // For instance accessors or static in 2022-03, pass 'this' and value + vec![ + Expr::This(ThisExpr { span: accessor.span }).as_arg(), + Expr::Ident(Ident::new("v".into(), accessor.span, Default::default())).as_arg() + ] }; - let setter = PrivateMethod { - span: DUMMY_SP, - key: key.clone(), - function: setter_function, + + new_members.push(ClassMember::Method(ClassMethod { + span: accessor.span, + key, + function: Box::new(Function { + params: vec![Param { + span: accessor.span, + decorators: Vec::new(), + pat: Pat::Ident(BindingIdent { + id: Ident::new("v".into(), accessor.span, Default::default()), + type_ann: None, + }), + }], + decorators: Vec::new(), + span: accessor.span, + ctxt: Default::default(), + body: Some(BlockStmt { + span: accessor.span, + ctxt: Default::default(), + stmts: vec![Stmt::Expr(ExprStmt { + span: accessor.span, + expr: Box::new(Expr::Call(CallExpr { + span: accessor.span, + ctxt: Default::default(), + callee: set_id_ref.clone().as_callee(), + args: setter_args, + type_args: None, + })), + })], + }), + is_generator: false, + is_async: false, + type_params: None, + return_type: None, + }), kind: MethodKind::Setter, is_static: accessor.is_static, accessibility: None, is_abstract: false, is_optional: false, is_override: false, - }; - - new.push(ClassMember::PrivateProp(private_field)); - new.push(ClassMember::PrivateMethod(getter)); - new.push(ClassMember::PrivateMethod(setter)); + })); } - Key::Public(key) => { - let getter = ClassMethod { - span: DUMMY_SP, + Key::Private(key) => { + // Add private getter + // Create the getter arguments for private accessors + let private_getter_args = if accessor.is_static && self.version == DecoratorVersion::V202311 { + // For static private accessors in 2023-11, no args + vec![] + } else { + // For instance private accessors or static in 2022-03, pass 'this' + vec![Expr::This(ThisExpr { span: accessor.span }).as_arg()] + }; + + new_members.push(ClassMember::PrivateMethod(PrivateMethod { + span: accessor.span, key: key.clone(), - function: getter_function, + function: Box::new(Function { + params: Vec::new(), + decorators: Vec::new(), + span: accessor.span, + ctxt: Default::default(), + body: Some(BlockStmt { + span: accessor.span, + ctxt: Default::default(), + stmts: vec![Stmt::Return(ReturnStmt { + span: accessor.span, + arg: Some(Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: get_id_ref.clone().as_callee(), + args: private_getter_args, + type_args: None, + }))), + })], + }), + is_generator: false, + is_async: false, + type_params: None, + return_type: None, + }), kind: MethodKind::Getter, is_static: accessor.is_static, accessibility: None, is_abstract: false, is_optional: false, is_override: false, + })); + + // Add private setter + // Create the setter arguments for private accessors + let private_setter_args = if accessor.is_static && self.version == DecoratorVersion::V202311 { + // For static private accessors in 2023-11, only the value + vec![Expr::Ident(Ident::new("v".into(), accessor.span, Default::default())).as_arg()] + } else { + // For instance private accessors or static in 2022-03, pass 'this' and value + vec![ + Expr::This(ThisExpr { span: accessor.span }).as_arg(), + Expr::Ident(Ident::new("v".into(), accessor.span, Default::default())).as_arg() + ] }; - let setter = ClassMethod { - span: DUMMY_SP, - key: key.clone(), - function: setter_function, + + new_members.push(ClassMember::PrivateMethod(PrivateMethod { + span: accessor.span, + key, + function: Box::new(Function { + params: vec![Param { + span: accessor.span, + decorators: Vec::new(), + pat: Pat::Ident(BindingIdent { + id: Ident::new("v".into(), accessor.span, Default::default()), + type_ann: None, + }), + }], + decorators: Vec::new(), + span: accessor.span, + ctxt: Default::default(), + body: Some(BlockStmt { + span: accessor.span, + ctxt: Default::default(), + stmts: vec![Stmt::Expr(ExprStmt { + span: accessor.span, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: set_id_ref.clone().as_callee(), + args: private_setter_args, + type_args: None, + })), + })], + }), + is_generator: false, + is_async: false, + type_params: None, + return_type: None, + }), kind: MethodKind::Setter, is_static: accessor.is_static, accessibility: None, is_abstract: false, is_optional: false, is_override: false, - }; - - new.push(ClassMember::PrivateProp(private_field)); - new.push(ClassMember::Method(getter)); - new.push(ClassMember::Method(setter)); + })); } } - continue; + // Add field initialization - separate init and init_extra calls + if accessor.is_static { + // For static accessors, fix initialization to use correct class reference + let static_init_call = if self.version == DecoratorVersion::V202311 { + // For 2023-11, static init should reference the class, not 'this' + init_call + } else { + // For 2022-03, use 'this' + init_call + }; + + static_field_initializer_expressions.push(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })), + prop: MemberProp::PrivateName(private_key.clone()), + })), + right: Box::new(static_init_call), + })); + // For 2023-11, add init_extra call to static block + if let Some(ref extra_id) = init_extra_id { + static_field_initializer_expressions.push(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: extra_id.clone().as_callee(), + args: vec![], + type_args: None, + })); + } + } else { + field_initializer_expressions.push(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })), + prop: MemberProp::PrivateName(private_key.clone()), + })), + right: Box::new(init_call), + })); + // For 2023-11, add init_extra call to constructor + if let Some(ref extra_id) = init_extra_id { + field_initializer_expressions.push(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: extra_id.clone().as_callee(), + args: vec![Expr::This(ThisExpr { span: DUMMY_SP }).as_arg()], + type_args: None, + })); + } + } } + ClassMember::Method(mut method) if !method.function.decorators.is_empty() => { + has_decorators = true; + + let base_kind = match method.kind { + MethodKind::Method => METHOD, + MethodKind::Getter => GETTER, + MethodKind::Setter => SETTER, + }; + + let kind_value = if method.is_static { + match self.version { + DecoratorVersion::V202311 => STATIC + base_kind, + _ => STATIC_OLD_VERSION + base_kind + } + } else { + base_kind + }; + + // Handle multiple decorators + let decorator_expr = if method.function.decorators.len() == 1 { + method.function.decorators[0].expr.clone() + } else { + Box::new(Expr::Array(ArrayLit { + span: DUMMY_SP, + elems: method.function.decorators.iter().map(|d| Some(d.expr.clone().as_arg())).collect(), + })) + }; + + let element_desc = ArrayLit { + span: DUMMY_SP, + elems: vec![ + Some(decorator_expr.as_arg()), + Some(Lit::Num(Number { span: DUMMY_SP, value: kind_value, raw: None }).as_arg()), + Some(match &method.key { + PropName::Ident(id) => Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: id.sym.clone(), + raw: None, + })), + PropName::Str(s) => Expr::Lit(Lit::Str(s.clone())), + PropName::Computed(computed) => *computed.expr.clone(), + _ => Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: "method".into(), + raw: None, + })) + }.as_arg()), + ], + }; + element_decs.push(element_desc.as_arg()); - ClassMember::Method(..) | ClassMember::PrivateMethod(..) => { - m.visit_mut_with(self); - } + // For instance methods, add protoInit call + if !method.is_static { + if proto_init_local.is_none() { + proto_init_local = Some(Ident::new("_initProto".into(), DUMMY_SP, Default::default())); + } + } else { + if static_init_local.is_none() { + static_init_local = Some(Ident::new("_initStatic".into(), DUMMY_SP, Default::default())); + } + } - _ => {} - } + // Clear decorators from method + method.function.decorators.clear(); - new.push(m); - } + new_members.push(ClassMember::Method(method)); + } + ClassMember::PrivateMethod(mut method) if !method.function.decorators.is_empty() => { + has_decorators = true; + + // Create element descriptor [decorator(s), kind, name] + let base_kind = match method.kind { + MethodKind::Method => METHOD, + MethodKind::Getter => GETTER, + MethodKind::Setter => SETTER, + }; + + let kind_value = if method.is_static { + match self.version { + DecoratorVersion::V202311 => STATIC + base_kind, + _ => STATIC_OLD_VERSION + base_kind + } + } else { + base_kind + }; + + // Handle multiple decorators + let decorator_expr = if method.function.decorators.len() == 1 { + method.function.decorators[0].expr.clone() + } else { + Box::new(Expr::Array(ArrayLit { + span: DUMMY_SP, + elems: method.function.decorators.iter().map(|d| Some(d.expr.clone().as_arg())).collect(), + })) + }; + + let element_desc = ArrayLit { + span: DUMMY_SP, + elems: vec![ + Some(decorator_expr.as_arg()), + Some(Lit::Num(Number { span: DUMMY_SP, value: kind_value, raw: None }).as_arg()), + Some(Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: method.key.name.clone(), + raw: None, + })).as_arg()), + ], + }; + element_decs.push(element_desc.as_arg()); - for mut m in new.take() { - match m { - ClassMember::Method(..) - | ClassMember::PrivateMethod(..) - | ClassMember::AutoAccessor(..) => {} + // For instance methods, add protoInit call + if !method.is_static { + if proto_init_local.is_none() { + proto_init_local = Some(Ident::new("_initProto".into(), DUMMY_SP, Default::default())); + } + } else { + if static_init_local.is_none() { + static_init_local = Some(Ident::new("_initStatic".into(), DUMMY_SP, Default::default())); + } + } + // Clear decorators from method + method.function.decorators.clear(); + + new_members.push(ClassMember::PrivateMethod(method)); + } + ClassMember::AutoAccessor(accessor) => { + // Transform auto-accessor to getter/setter + new_members.extend(self.transform_auto_accessor(accessor)); + } _ => { - if !m.span().is_dummy() { - m.visit_mut_with(self); - } + new_members.push(member); } } - - new.push(m); } - *members = new; - } - - fn visit_mut_class_method(&mut self, n: &mut ClassMethod) { - // method without body is TypeScript's method declaration. - if n.function.body.is_none() { - return; + if !has_decorators { + class.body = new_members; + return (class, extra_stmts); } - n.visit_mut_children_with(self); - - if n.function.decorators.is_empty() { - return; - } + // Clear decorators from class + class.decorators.clear(); + class.body = new_members; - let decorators = self.preserve_side_effect_of_decorators(n.function.decorators.take()); - let dec = merge_decorators(decorators); + // Generate helper calls and variable declarations + let helper_name = match self.version { + DecoratorVersion::V202203 => { + enable_helper!(apply_decs_2203_r); + "_apply_decs_2203_r" + } + DecoratorVersion::V202311 => { + enable_helper!(apply_decs_2311); + "_apply_decs_2311" + } + _ => { + enable_helper!(apply_decs_2203_r); + "_apply_decs_2203_r" + } + }; - let (name, _init) = self.initializer_name(&mut n.key, "call"); + // Create variable declarations - build the list of all variables that need to be declared + let has_class_decs = !class_decs.is_empty(); + let mut all_var_decls = Vec::new(); - if n.is_static { - self.state - .init_static - .get_or_insert_with(|| private_ident!("_initStatic")); - } else { - self.state - .init_proto - .get_or_insert_with(|| private_ident!("_initProto")); + // Add _initClass and _initProto if needed + if has_class_decs { + all_var_decls.push(VarDeclarator { + span: DUMMY_SP, + name: Ident::new("_initClass".into(), DUMMY_SP, Default::default()).into(), + init: None, + definite: false, + }); } - - let arg = Some( - ArrayLit { + if let Some(proto_init) = &proto_init_local { + all_var_decls.push(VarDeclarator { span: DUMMY_SP, - elems: vec![ - dec, - Some( - match (n.is_static, n.kind) { - (true, MethodKind::Method) => 7, - (false, MethodKind::Method) => 2, - (true, MethodKind::Setter) => 9, - (false, MethodKind::Setter) => 4, - (true, MethodKind::Getter) => 8, - (false, MethodKind::Getter) => 3, - } - .as_arg(), - ), - Some(name.as_arg()), - ], - } - .as_arg(), - ); - if n.is_static { - self.state.init_static_args.push(arg); - } else { - self.state.init_proto_args.push(arg); + name: proto_init.clone().into(), + init: None, + definite: false, + }); } - } - - fn visit_mut_class_prop(&mut self, p: &mut ClassProp) { - if p.declare { - return; + if let Some(static_init) = &static_init_local { + all_var_decls.push(VarDeclarator { + span: DUMMY_SP, + name: static_init.clone().into(), + init: None, + definite: false, + }); } - p.visit_mut_children_with(self); - - if p.decorators.is_empty() { - return; + // Add init_vars (field initializers) + for var in &init_vars { + all_var_decls.push(VarDeclarator { + span: DUMMY_SP, + name: var.clone().into(), + init: None, + definite: false, + }); } - let decorators = self.preserve_side_effect_of_decorators(p.decorators.take()); - let dec = merge_decorators(decorators); + // Declare all variables with var at the top level + if !all_var_decls.is_empty() { + extra_stmts.push(Stmt::Decl(Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + ctxt: Default::default(), + kind: VarDeclKind::Var, // Use var for 2022-03 compatibility + declare: false, + decls: all_var_decls, + })))); + } - let (name, init) = self.initializer_name(&mut p.key, "init"); + // Declare class variables separately with let + if has_class_decs { + extra_stmts.push(Stmt::Decl(Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + ctxt: Default::default(), + kind: VarDeclKind::Let, + declare: false, + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: Ident::new("_C".into(), DUMMY_SP, Default::default()).into(), + init: None, + definite: false, + }], + })))); + } - self.extra_vars.push(VarDeclarator { - span: p.span, - name: init.clone().into(), - init: None, - definite: false, - }); + // Create apply_decs call - first argument is always 'this' + let mut args = vec![Expr::This(ThisExpr { span: DUMMY_SP }).as_arg()]; + + // Element decorators array (second parameter for both versions) + args.push(ArrayLit { + span: DUMMY_SP, + elems: element_decs.into_iter().map(Some).collect(), + }.as_arg()); + + // Class decorators array (third parameter for both versions) + args.push(ArrayLit { + span: DUMMY_SP, + elems: if has_class_decs { + class_decs.into_iter().map(|expr| Some(expr.as_arg())).collect() + } else { + vec![] + }, + }.as_arg()); - p.value = Some( - CallExpr { - span: DUMMY_SP, - callee: init.clone().as_callee(), - args: once(ThisExpr { span: DUMMY_SP }.as_arg()) - .chain(p.value.take().map(|v| v.as_arg())) - .collect(), + let apply_call = CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: Ident::new(helper_name.into(), DUMMY_SP, Default::default()).as_callee(), + args, + type_args: None, + }; - ..Default::default() - } - .into(), - ); + // Create destructuring assignment + let mut props = Vec::new(); + + // Build element decorators list (init_vars + proto_init_local + static_init_local) + let mut element_vars = init_vars.clone(); + if let Some(proto_init) = &proto_init_local { + element_vars.push(proto_init.clone()); + } + if let Some(static_init) = &static_init_local { + element_vars.push(static_init.clone()); + } + + if !element_vars.is_empty() { + props.push(ObjectPatProp::KeyValue(KeyValuePatProp { + key: PropName::Ident(quote_ident!("e")), + value: Box::new(Pat::Array(ArrayPat { + span: DUMMY_SP, + elems: element_vars.iter().map(|v| Some(v.clone().into())).collect(), + optional: false, + type_ann: None, + })), + })); + } - let initialize_init = { - Some( - ArrayLit { + if has_class_decs { + props.push(ObjectPatProp::KeyValue(KeyValuePatProp { + key: PropName::Ident(quote_ident!("c")), + value: Box::new(Pat::Array(ArrayPat { span: DUMMY_SP, elems: vec![ - dec, - Some(if p.is_static { 5.as_arg() } else { 0.as_arg() }), - Some(name.as_arg()), + Some(Pat::Ident(BindingIdent { + id: Ident::new("_C".into(), DUMMY_SP, Default::default()), + type_ann: None, + })), + Some(Pat::Ident(BindingIdent { + id: Ident::new("_initClass".into(), DUMMY_SP, Default::default()), + type_ann: None, + })), ], - } - .as_arg(), - ) - }; - - if p.is_static { - self.state.static_lhs.push(init); - self.state.init_static_args.push(initialize_init); - } else { - self.state.proto_lhs.push(init); - self.state.init_proto_args.push(initialize_init); + optional: false, + type_ann: None, + })), + })); } - } - fn visit_mut_expr(&mut self, e: &mut Expr) { - if let Expr::Class(c) = e { - if !c.class.decorators.is_empty() { - let new = self.handle_class_expr(&mut c.class, c.ident.as_ref()); - - c.visit_mut_with(self); + // Add static block with destructuring + if !element_vars.is_empty() || has_class_decs { + let destructuring_target = if !element_vars.is_empty() && has_class_decs { + // Both element and class decorators: { e: [...], c: [...] } = _apply_decs_2203_r(...) + AssignTarget::Pat(AssignTargetPat::Object(ObjectPat { + span: DUMMY_SP, + props, + optional: false, + type_ann: None, + })) + } else if !element_vars.is_empty() { + // Only element decorators: [_init_a, _init_b] = _apply_decs_2203_r(...).e + AssignTarget::Pat(AssignTargetPat::Array(ArrayPat { + span: DUMMY_SP, + elems: element_vars.iter().map(|v| Some(v.clone().into())).collect(), + optional: false, + type_ann: None, + })) + } else { + // Only class decorators: [_C, _initClass] = _apply_decs_2203_r(...).c + AssignTarget::Pat(AssignTargetPat::Array(ArrayPat { + span: DUMMY_SP, + elems: vec![ + Some(Pat::Ident(BindingIdent { + id: Ident::new("_C".into(), DUMMY_SP, Default::default()), + type_ann: None, + })), + Some(Pat::Ident(BindingIdent { + id: Ident::new("_initClass".into(), DUMMY_SP, Default::default()), + type_ann: None, + })), + ], + optional: false, + type_ann: None, + })) + }; - *e = SeqExpr { + let assign_expr = if !element_vars.is_empty() && !has_class_decs { + // For element-only decorators, access .e property + Box::new(Expr::Member(MemberExpr { span: DUMMY_SP, - exprs: vec![Box::new(e.take()), Box::new(Expr::Ident(new))], - } - .into(); + obj: Box::new(apply_call.into()), + prop: MemberProp::Ident(quote_ident!("e")), + })) + } else if element_vars.is_empty() && has_class_decs { + // For class-only decorators, access .c property + Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(apply_call.into()), + prop: MemberProp::Ident(quote_ident!("c")), + })) + } else { + // For both, use the full object + Box::new(apply_call.into()) + }; - return; - } + let static_block = ClassMember::StaticBlock(StaticBlock { + span: DUMMY_SP, + body: BlockStmt { + span: DUMMY_SP, + ctxt: Default::default(), + stmts: vec![Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: destructuring_target, + right: assign_expr, + })), + })], + }, + }); + // Insert the static block at the beginning of the class + class.body.insert(0, static_block); } - maybe_grow_default(|| e.visit_mut_children_with(self)); - } + // Add initClass call if needed + if has_class_decs { + // For 2023-11, class decorators return an init function that should be called + class.body.push(ClassMember::StaticBlock(StaticBlock { + span: DUMMY_SP, + body: BlockStmt { + span: DUMMY_SP, + ctxt: Default::default(), + stmts: vec![Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: Ident::new("_initClass".into(), DUMMY_SP, Default::default()).as_callee(), + args: vec![], + type_args: None, + })), + })], + }, + })); + } - fn visit_mut_module_item(&mut self, s: &mut ModuleItem) { - match s { - ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl { - span, - decl: Decl::Class(c), - })) if !c.class.decorators.is_empty() => { - let ident = c.ident.clone(); - let span = *span; - let new_stmt = self.handle_class_decl(c); - - *s = new_stmt.into(); - self.extra_exports - .push(ExportSpecifier::Named(ExportNamedSpecifier { - span, - orig: ModuleExportName::Ident(ident), - exported: None, - is_type_only: false, - })); + // Add protoInit call to constructor if needed + if let Some(proto_init) = &proto_init_local { + // Find or create constructor + let mut constructor_idx = None; + for (idx, member) in class.body.iter().enumerate() { + if let ClassMember::Constructor(_ctor) = member { + constructor_idx = Some(idx); + break; + } } - ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(ExportDefaultDecl { - span, - decl: DefaultDecl::Class(c), - })) if !c.class.decorators.is_empty() => { - let ident = c - .ident - .get_or_insert_with(|| private_ident!("_default")) - .clone(); - - let mut class_decl = c.take().as_class_decl().unwrap(); - let new_stmt = self.handle_class_decl(&mut class_decl); - - self.extra_exports - .push(ExportSpecifier::Named(ExportNamedSpecifier { - span: *span, - orig: ModuleExportName::Ident(ident), - exported: Some(quote_ident!("default").into()), - is_type_only: false, + + let proto_init_call = Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: proto_init.clone().as_callee(), + args: vec![Expr::This(ThisExpr { span: DUMMY_SP }).as_arg()], + type_args: None, + })), + }); + + if let Some(idx) = constructor_idx { + // Insert into existing constructor + if let ClassMember::Constructor(ctor) = &mut class.body[idx] { + // Insert at beginning of constructor (or after super call if it exists) + let mut super_idx = None; + for (stmt_idx, stmt) in ctor.body.as_mut().unwrap().stmts.iter().enumerate() { + if let Stmt::Expr(ExprStmt { expr, .. }) = stmt { + if let Expr::Call(CallExpr { callee, .. }) = &**expr { + if matches!(callee, Callee::Super(_)) { + super_idx = Some(stmt_idx); + break; + } + } + } + } + + if let Some(idx) = super_idx { + // Insert after super call + ctor.body.as_mut().unwrap().stmts.insert(idx + 1, proto_init_call); + } else { + // No super call, insert at beginning + ctor.body.as_mut().unwrap().stmts.insert(0, proto_init_call); + } + } + } else { + // Create new constructor + let has_super = class.super_class.is_some(); + let mut ctor_stmts = vec![]; + + if has_super { + ctor_stmts.push(Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: Callee::Super(Super { span: DUMMY_SP }), + args: vec![ExprOrSpread { + spread: Some(DUMMY_SP), + expr: Box::new(Expr::Ident(Ident::new("args".into(), DUMMY_SP, Default::default()))), + }], + type_args: None, + })), })); + } + + ctor_stmts.push(proto_init_call); - *s = new_stmt.into(); - } - _ => { - s.visit_mut_children_with(self); + class.body.insert(0, ClassMember::Constructor(Constructor { + span: DUMMY_SP, + ctxt: Default::default(), + key: PropName::Ident(quote_ident!("constructor")), + params: if has_super { + vec![ParamOrTsParamProp::Param(Param { + span: DUMMY_SP, + decorators: vec![], + pat: Pat::Rest(RestPat { + span: DUMMY_SP, + arg: Box::new(Pat::Ident(BindingIdent { + id: Ident::new("args".into(), DUMMY_SP, Default::default()), + type_ann: None, + })), + type_ann: None, + dot3_token: DUMMY_SP, + }), + })] + } else { + vec![] + }, + body: Some(BlockStmt { + span: DUMMY_SP, + ctxt: Default::default(), + stmts: ctor_stmts, + }), + accessibility: None, + is_optional: false, + })); } } - } - fn visit_mut_module_items(&mut self, n: &mut Vec) { - let extra_vars = self.extra_vars.take(); - let extra_lets = self.extra_lets.take(); - let pre_class_inits = self.pre_class_inits.take(); - let extra_exports = self.extra_exports.take(); - - let mut insert_builder = InsertPassBuilder::new(); + // Handle field initializer expressions + if !field_initializer_expressions.is_empty() { + // Find or create constructor + let mut constructor_idx = None; + for (idx, member) in class.body.iter().enumerate() { + if let ClassMember::Constructor(_ctor) = member { + constructor_idx = Some(idx); + break; + } + } - for (index, n) in n.iter_mut().enumerate() { - n.visit_mut_with(self); - if !self.extra_lets.is_empty() { - insert_builder.push_back( - index, - VarDecl { - span: DUMMY_SP, - kind: VarDeclKind::Let, - decls: self.extra_lets.take(), - declare: false, - ..Default::default() + if let Some(idx) = constructor_idx { + // Insert into existing constructor + if let ClassMember::Constructor(ctor) = &mut class.body[idx] { + let init_stmts: Vec = field_initializer_expressions + .into_iter() + .map(|expr| Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(expr), + })) + .collect(); + + // Insert after super() call if it exists + let mut super_idx = None; + for (stmt_idx, stmt) in ctor.body.as_mut().unwrap().stmts.iter().enumerate() { + if let Stmt::Expr(ExprStmt { expr, .. }) = stmt { + if let Expr::Call(CallExpr { callee, .. }) = &**expr { + if matches!(callee, Callee::Super(_)) { + super_idx = Some(stmt_idx); + break; + } + } + } } - .into(), - ); - } - if !self.pre_class_inits.is_empty() { - insert_builder.push_back( - index, - ExprStmt { - span: DUMMY_SP, - expr: Expr::from_exprs(self.pre_class_inits.take()), + + if let Some(idx) = super_idx { + // Insert after super call + ctor.body.as_mut().unwrap().stmts.splice(idx + 1..idx + 1, init_stmts); + } else { + // No super call, insert at beginning + ctor.body.as_mut().unwrap().stmts.splice(0..0, init_stmts); } - .into(), - ); - } - } - - if !self.extra_vars.is_empty() { - let insert_pos = n - .iter() - .position(|module_item| match module_item { - ModuleItem::Stmt(stmt) => !is_maybe_branch_directive(stmt), - ModuleItem::ModuleDecl(_) => true, - }) - .unwrap_or(0); - insert_builder.push_front( - insert_pos, - VarDecl { - span: DUMMY_SP, - kind: VarDeclKind::Var, - decls: self.extra_vars.take(), - declare: false, - ..Default::default() } - .into(), - ); - } + } else { + // Create new constructor + let has_super = class.super_class.is_some(); + let mut ctor_stmts = vec![]; + + if has_super { + ctor_stmts.push(Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + ctxt: Default::default(), + callee: Callee::Super(Super { span: DUMMY_SP }), + args: vec![ExprOrSpread { + spread: Some(DUMMY_SP), + expr: Box::new(Expr::Ident(Ident::new("args".into(), DUMMY_SP, Default::default()))), + }], + type_args: None, + })), + })); + } + + ctor_stmts.extend(field_initializer_expressions.into_iter().map(|expr| { + Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(expr), + }) + })); - if !self.extra_exports.is_empty() { - insert_builder.push_back( - n.len() + 1, - NamedExport { + class.body.insert(0, ClassMember::Constructor(Constructor { span: DUMMY_SP, - specifiers: self.extra_exports.take(), - src: None, - type_only: false, - with: None, - } - .into(), - ); + ctxt: Default::default(), + key: PropName::Ident(quote_ident!("constructor")), + params: vec![], + body: Some(BlockStmt { + span: DUMMY_SP, + ctxt: Default::default(), + stmts: ctor_stmts, + }), + accessibility: None, + is_optional: false, + })); + } } - *n = insert_builder.build(n.take()); - - if !self.rename_map.is_empty() { - n.visit_mut_with(&mut IdentRenamer::new(&self.rename_map)); + // Handle static field initializer expressions + if !static_field_initializer_expressions.is_empty() { + class.body.push(ClassMember::StaticBlock(StaticBlock { + span: DUMMY_SP, + body: BlockStmt { + span: DUMMY_SP, + ctxt: Default::default(), + stmts: static_field_initializer_expressions.into_iter().map(|expr| { + Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(expr), + }) + }).collect(), + }, + })); } - self.extra_vars = extra_vars; - self.extra_lets = extra_lets; - self.pre_class_inits = pre_class_inits; - self.extra_exports = extra_exports; + (class, extra_stmts) } - fn visit_mut_private_prop(&mut self, p: &mut PrivateProp) { - p.visit_mut_children_with(self); - - if p.decorators.is_empty() { - return; - } - - let decorators = self.preserve_side_effect_of_decorators(p.decorators.take()); - let dec = merge_decorators(decorators); - - let init = private_ident!(format!("_init_{}", p.key.name)); - - self.extra_vars.push(VarDeclarator { - span: p.span, - name: init.clone().into(), - init: None, - definite: false, - }); - - p.value = Some( - CallExpr { - span: DUMMY_SP, - callee: init.clone().as_callee(), - args: once(ThisExpr { span: DUMMY_SP }.as_arg()) - .chain(p.value.take().map(|v| v.as_arg())) - .collect(), - ..Default::default() + fn transform_auto_accessor(&mut self, accessor: AutoAccessor) -> Vec { + let key = match &accessor.key { + Key::Public(prop_name) => prop_name.clone(), + Key::Private(private_name) => PropName::Ident(private_name.name.clone().into()), + }; + + let is_static = accessor.is_static; + let value = accessor.value.clone(); + + // Create private field name + let private_key = if let PropName::Ident(ident) = &key { + PrivateName { + span: ident.span, + name: format!("__{}", ident.sym).into(), } - .into(), - ); - - let initialize_init = { - let access_expr = MemberExpr { - span: DUMMY_SP, - obj: ThisExpr { span: DUMMY_SP }.into(), - prop: MemberProp::PrivateName(p.key.clone()), - }; - - let getter = Box::new(Function { - span: DUMMY_SP, + } else { + PrivateName { + span: accessor.span, + name: "__accessor".into(), + } + }; + + let mut members = Vec::new(); + + // Add private field + members.push(ClassMember::PrivateProp(PrivateProp { + span: accessor.span, + ctxt: SyntaxContext::empty(), + key: private_key.clone(), + value, + type_ann: None, + is_static, + decorators: Vec::new(), + accessibility: None, + is_optional: false, + is_override: false, + readonly: false, + definite: false, + })); + + // Add getter + members.push(ClassMember::Method(ClassMethod { + span: accessor.span, + key: key.clone(), + function: Box::new(Function { + params: Vec::new(), + decorators: Vec::new(), + span: accessor.span, + ctxt: SyntaxContext::empty(), body: Some(BlockStmt { - span: DUMMY_SP, + span: accessor.span, + ctxt: SyntaxContext::empty(), stmts: vec![Stmt::Return(ReturnStmt { - span: DUMMY_SP, - arg: Some(access_expr.clone().into()), + span: accessor.span, + arg: Some(Box::new(Expr::Member(MemberExpr { + span: accessor.span, + obj: Box::new(Expr::This(ThisExpr { span: accessor.span })), + prop: MemberProp::PrivateName(private_key.clone()), + }))), })], - ..Default::default() }), - is_async: false, is_generator: false, - ..Default::default() - }); - let settter_arg = private_ident!("value"); - let setter = Box::new(Function { - span: DUMMY_SP, + is_async: false, + type_params: None, + return_type: None, + }), + kind: MethodKind::Getter, + is_static, + accessibility: None, + is_abstract: false, + is_optional: false, + is_override: false, + })); + + // Add setter + members.push(ClassMember::Method(ClassMethod { + span: accessor.span, + key: key.clone(), + function: Box::new(Function { + params: vec![Param { + span: accessor.span, + decorators: Vec::new(), + pat: Pat::Ident(BindingIdent { + id: Ident::new("value".into(), accessor.span, SyntaxContext::empty()), + type_ann: None, + }), + }], + decorators: Vec::new(), + span: accessor.span, + ctxt: SyntaxContext::empty(), body: Some(BlockStmt { - span: DUMMY_SP, + span: accessor.span, + ctxt: SyntaxContext::empty(), stmts: vec![Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: accessor.span, expr: Box::new(Expr::Assign(AssignExpr { - span: DUMMY_SP, - op: op!("="), - left: access_expr.into(), - right: Box::new(Expr::Ident(settter_arg.clone())), + span: accessor.span, + op: AssignOp::Assign, + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { + span: accessor.span, + obj: Box::new(Expr::This(ThisExpr { span: accessor.span })), + prop: MemberProp::PrivateName(private_key), + })), + right: Box::new(Expr::Ident(Ident::new("value".into(), accessor.span, SyntaxContext::empty()))), })), })], - ..Default::default() }), - is_async: false, is_generator: false, - decorators: Default::default(), - params: vec![Param { - span: DUMMY_SP, - decorators: Default::default(), - pat: Pat::Ident(settter_arg.into()), - }], - ..Default::default() - }); - - ArrayLit { - span: DUMMY_SP, - elems: vec![ - dec, - Some(if p.is_static { 5.as_arg() } else { 0.as_arg() }), - Some((&*p.key.name).as_arg()), - Some( - FnExpr { - ident: None, - function: getter, - } - .as_arg(), - ), - Some( - FnExpr { - ident: None, - function: setter, - } - .as_arg(), - ), - ], - } - .as_arg() - }; - - if p.is_static { - self.state.static_lhs.push(init); - self.state.init_static_args.push(Some(initialize_init)); - } else { - self.state.proto_lhs.push(init); - self.state.init_proto_args.push(Some(initialize_init)); - } + is_async: false, + type_params: None, + return_type: None, + }), + kind: MethodKind::Setter, + is_static, + accessibility: None, + is_abstract: false, + is_optional: false, + is_override: false, + })); + + members } +} - fn visit_mut_stmt(&mut self, s: &mut Stmt) { - match s { - Stmt::Decl(Decl::Class(c)) if !c.class.decorators.is_empty() => { - *s = self.handle_class_decl(c); - } - _ => { - s.visit_mut_children_with(self); +impl Fold for DecoratorTransform { + noop_fold_type!(); + + fn fold_block_stmt(&mut self, block: BlockStmt) -> BlockStmt { + let mut new_stmts = Vec::new(); + + for stmt in block.stmts { + match stmt { + Stmt::Decl(Decl::Class(ClassDecl { ident, declare: false, class })) => { + let has_decorators = !class.decorators.is_empty() || + class.body.iter().any(|member| match member { + ClassMember::Method(method) => !method.function.decorators.is_empty(), + ClassMember::PrivateMethod(method) => !method.function.decorators.is_empty(), + ClassMember::ClassProp(prop) => !prop.decorators.is_empty(), + ClassMember::PrivateProp(prop) => !prop.decorators.is_empty(), + ClassMember::AutoAccessor(accessor) => !accessor.decorators.is_empty(), + _ => false, + }); + + if has_decorators { + // For class declarations with decorators, expand into variable declarations + class + let (transformed_class, extra_stmts) = self.transform_class_with_decorators(*class); + + // Add variable declarations first + new_stmts.extend(extra_stmts); + + // Then add the transformed class + new_stmts.push(Stmt::Decl(Decl::Class(ClassDecl { + ident, + declare: false, + class: Box::new(transformed_class), + }))); + } else { + new_stmts.push(Stmt::Decl(Decl::Class(ClassDecl { + ident, + declare: false, + class: Box::new(self.fold_class(*class)), + }))); + } + } + _ => { + new_stmts.push(stmt.fold_with(self)); + } } } + + BlockStmt { + stmts: new_stmts, + ..block + } } - fn visit_mut_stmts(&mut self, n: &mut Vec) { - let old_state = take(&mut self.state); - let old_pre_class_inits = self.pre_class_inits.take(); - let old_extra_lets = self.extra_lets.take(); - let old_extra_vars = self.extra_vars.take(); - - let mut insert_builder = InsertPassBuilder::new(); - for (index, n) in n.iter_mut().enumerate() { - n.visit_mut_with(self); - if !self.extra_lets.is_empty() { - insert_builder.push_back( - index, - VarDecl { + fn fold_expr(&mut self, expr: Expr) -> Expr { + match expr { + Expr::Class(ClassExpr { ident, class }) => { + let has_decorators = !class.decorators.is_empty() || + class.body.iter().any(|member| match member { + ClassMember::Method(method) => !method.function.decorators.is_empty(), + ClassMember::PrivateMethod(method) => !method.function.decorators.is_empty(), + ClassMember::ClassProp(prop) => !prop.decorators.is_empty(), + ClassMember::PrivateProp(prop) => !prop.decorators.is_empty(), + ClassMember::AutoAccessor(accessor) => !accessor.decorators.is_empty(), + _ => false, + }); + + if has_decorators { + let (transformed_class, extra_stmts) = self.transform_class_with_decorators(*class); + + // For class expressions with decorators, we need to wrap them in an IIFE + // that declares the variables and then returns the class + let mut iife_stmts = extra_stmts; + + // Add the class expression as the return value + iife_stmts.push(Stmt::Return(ReturnStmt { span: DUMMY_SP, - kind: VarDeclKind::Let, - decls: self.extra_lets.take(), - declare: false, - ..Default::default() - } - .into(), - ); - } - if !self.pre_class_inits.is_empty() { - insert_builder.push_back( - index, - ExprStmt { + arg: Some(Box::new(Expr::Class(ClassExpr { + ident, + class: Box::new(transformed_class), + }))), + })); + + // Create IIFE + Expr::Call(CallExpr { span: DUMMY_SP, - expr: Expr::from_exprs(self.pre_class_inits.take()), - } - .into(), - ); + ctxt: Default::default(), + callee: Expr::Paren(ParenExpr { + span: DUMMY_SP, + expr: Box::new(Expr::Fn(FnExpr { + ident: None, + function: Box::new(Function { + params: vec![], + decorators: vec![], + span: DUMMY_SP, + ctxt: Default::default(), + body: Some(BlockStmt { + span: DUMMY_SP, + ctxt: Default::default(), + stmts: iife_stmts, + }), + is_generator: false, + is_async: false, + type_params: None, + return_type: None, + }), + })), + }).as_callee(), + args: vec![], + type_args: None, + }) + } else { + Expr::Class(ClassExpr { + ident, + class: Box::new(self.fold_class(*class)), + }) + } } + _ => expr.fold_children_with(self) } + } - if !self.extra_vars.is_empty() { - let insert_pos = n - .iter() - .position(|stmt| !is_maybe_branch_directive(stmt)) - .unwrap_or(0); - insert_builder.push_front( - insert_pos, - VarDecl { - span: DUMMY_SP, - kind: VarDeclKind::Var, - decls: self.extra_vars.take(), - declare: false, - ..Default::default() + fn fold_class(&mut self, class: Class) -> Class { + // Check if class has decorators or decorated members + let has_decorators = !class.decorators.is_empty() || + class.body.iter().any(|member| match member { + ClassMember::Method(method) => !method.function.decorators.is_empty(), + ClassMember::PrivateMethod(method) => !method.function.decorators.is_empty(), + ClassMember::ClassProp(prop) => !prop.decorators.is_empty(), + ClassMember::PrivateProp(prop) => !prop.decorators.is_empty(), + ClassMember::AutoAccessor(accessor) => !accessor.decorators.is_empty(), + _ => false, + }); + + let has_auto_accessors = class.body.iter().any(|member| matches!(member, ClassMember::AutoAccessor(_))); + + if has_decorators { + // For classes handled here, they should have been caught by fold_expr for expressions + // or fold_module for declarations. This is a fallback. + let (transformed_class, _extra_stmts) = self.transform_class_with_decorators(class); + transformed_class + } else if has_auto_accessors { + // Handle auto-accessors even without decorators + let mut new_members = Vec::new(); + for member in class.body { + match member { + ClassMember::AutoAccessor(accessor) => { + new_members.extend(self.transform_auto_accessor(accessor)); + } + _ => { + new_members.push(member); + } } - .into(), - ); + } + Class { + body: new_members, + ..class + } + } else { + class } - - *n = insert_builder.build(n.take()); - - self.extra_vars = old_extra_vars; - self.extra_lets = old_extra_lets; - self.pre_class_inits = old_pre_class_inits; - self.state = old_state; } -} -/// Inserts into a vector on `build()` setting the correct -/// capacity. This is useful in scenarios where you're iterating -/// a vector to insert and all the inserts are in the order of -/// the iteration. -struct InsertPassBuilder { - inserts: VecDeque<(usize, T)>, -} + fn fold_module(&mut self, module: Module) -> Module { + let mut new_body = Vec::new(); + let mut extra_stmts = Vec::new(); -impl InsertPassBuilder { - pub fn new() -> Self { - Self { - inserts: Default::default(), - } - } + for item in module.body { + match item { + ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl { + ident, + declare: false, + class, + }))) => { + let has_decorators = !class.decorators.is_empty() || + class.body.iter().any(|member| match member { + ClassMember::Method(method) => !method.function.decorators.is_empty(), + ClassMember::PrivateMethod(method) => !method.function.decorators.is_empty(), + ClassMember::ClassProp(prop) => !prop.decorators.is_empty(), + ClassMember::PrivateProp(prop) => !prop.decorators.is_empty(), + ClassMember::AutoAccessor(accessor) => !accessor.decorators.is_empty(), + _ => false, + }); - pub fn push_front(&mut self, index: usize, item: T) { - if cfg!(debug_assertions) { - if let Some(past) = self.inserts.front() { - debug_assert!(past.0 >= index, "{} {}", past.0, index); + if has_decorators { + let (transformed_class, mut stmts) = self.transform_class_with_decorators(*class); + extra_stmts.append(&mut stmts); + new_body.push(ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl { + ident, + declare: false, + class: Box::new(transformed_class), + })))); + } else { + let transformed_class = self.fold_class(*class); + new_body.push(ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl { + ident, + declare: false, + class: Box::new(transformed_class), + })))); + } + } + _ => { + new_body.push(item.fold_with(self)); + } } } - self.inserts.push_front((index, item)); - } - pub fn push_back(&mut self, index: usize, item: T) { - if cfg!(debug_assertions) { - if let Some(past) = self.inserts.back() { - debug_assert!(past.0 <= index, "{} {}", past.0, index); - } + // Add extra statements at the beginning + for stmt in extra_stmts.into_iter().rev() { + new_body.insert(0, ModuleItem::Stmt(stmt)); } - self.inserts.push_back((index, item)); - } - pub fn build(mut self, original: Vec) -> Vec { - let capacity = original.len() + self.inserts.len(); - let mut new = Vec::with_capacity(capacity); - for (index, item) in original.into_iter().enumerate() { - while self - .inserts - .front() - .map(|(item_index, _)| *item_index == index) - .unwrap_or(false) - { - new.push(self.inserts.pop_front().unwrap().1); - } - new.push(item); + Module { + body: new_body, + ..module } - new.extend(self.inserts.into_iter().map(|v| v.1)); - - debug_assert!(new.len() == capacity, "len: {} / {}", new.len(), capacity); - new - } -} - -fn merge_decorators(decorators: Vec>) -> Option { - if decorators.len() == 1 { - return decorators.into_iter().next().unwrap(); } - - Some( - ArrayLit { - span: DUMMY_SP, - elems: decorators, - } - .as_arg(), - ) -} +} \ No newline at end of file diff --git a/crates/swc_ecma_transforms_proposal/src/lib.rs b/crates/swc_ecma_transforms_proposal/src/lib.rs index 196364016864..99b5c7dbd441 100644 --- a/crates/swc_ecma_transforms_proposal/src/lib.rs +++ b/crates/swc_ecma_transforms_proposal/src/lib.rs @@ -8,7 +8,7 @@ pub use self::{ import_attributes::import_attributes, }; -#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub enum DecoratorVersion { #[default] @@ -23,6 +23,7 @@ pub enum DecoratorVersion { } pub mod decorator_2022_03; +pub mod decorator_2023_11; mod decorator_impl; pub mod decorators; pub mod explicit_resource_management; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorator_evanw.rs b/crates/swc_ecma_transforms_proposal/tests/decorator_evanw.rs index 5ee0e0446103..cd9685f00025 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorator_evanw.rs +++ b/crates/swc_ecma_transforms_proposal/tests/decorator_evanw.rs @@ -1,7 +1,7 @@ use std::{fs, path::PathBuf}; use swc_ecma_parser::{EsSyntax, Syntax}; -use swc_ecma_transforms_proposal::decorator_2022_03::decorator_2022_03; +use swc_ecma_transforms_proposal::decorator_2023_11::decorator_2023_11; use swc_ecma_transforms_testing::exec_tr; const HELPERS: &str = r###" @@ -63,7 +63,7 @@ fn fixture(input: PathBuf) { auto_accessors: true, ..Default::default() }), - |_| decorator_2022_03(), + |_| decorator_2023_11(), &code, ); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators.rs b/crates/swc_ecma_transforms_proposal/tests/decorators.rs index ddc342e70dfe..c0c18068fe26 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators.rs +++ b/crates/swc_ecma_transforms_proposal/tests/decorators.rs @@ -10,7 +10,9 @@ use swc_common::{comments::SingleThreadedComments, Mark}; use swc_ecma_ast::Pass; use swc_ecma_parser::{EsSyntax, Syntax, TsSyntax}; use swc_ecma_transforms_base::{assumptions::Assumptions, resolver}; -use swc_ecma_transforms_proposal::{decorator_2022_03::decorator_2022_03, DecoratorVersion}; +use swc_ecma_transforms_proposal::{ + decorator_2022_03::decorator_2022_03, decorator_2023_11::decorator_2023_11, DecoratorVersion, +}; use swc_ecma_transforms_testing::{test_fixture, FixtureTestConfig}; use swc_ecma_visit::Fold; @@ -132,7 +134,7 @@ fn create_pass(comments: Rc, input: &Path) -> Box match &**name { - "proposal-class-properties" => { + "proposal-class-properties" | "transform-class-properties" => { add!(swc_ecma_transforms_compat::es2022::static_blocks()); add!(swc_ecma_transforms_compat::es2022::class_properties( Default::default(), @@ -141,7 +143,7 @@ fn create_pass(comments: Rc, input: &Path) -> Box { + "proposal-private-methods" | "transform-private-methods" => { add!(swc_ecma_transforms_compat::es2022::class_properties( Default::default(), unresolved_mark @@ -149,17 +151,19 @@ fn create_pass(comments: Rc, input: &Path) -> Box { + "proposal-class-static-block" | "transform-class-static-block" => { add!(swc_ecma_transforms_compat::es2022::static_blocks()); continue; } - _ => {} + _ => { + panic!("Unknown plugin: {}", name); + } }, BabelPluginEntry::WithConfig(name, config) => match &**name { "proposal-decorators" => match config { BabelPluginOption::Decorator { version } => match version { DecoratorVersion::V202311 => { - todo!() + add!(decorator_2023_11()); } DecoratorVersion::V202112 => todo!(), DecoratorVersion::V202203 => { diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/options.json deleted file mode 100644 index 443b4b4eb858..000000000000 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/options.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "plugins": [["proposal-decorators", { "version": "2022-03" }]], - "assumptions": { - "constantSuper": true - } -} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-nested-constructor-expression/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-nested-constructor-expression/output.js deleted file mode 100644 index 150f4e5d7474..000000000000 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-nested-constructor-expression/output.js +++ /dev/null @@ -1,14 +0,0 @@ -var _initClass; -const dec = () => { }; -let _Foo; -class Foo extends Bar { - static { - [_Foo, _initClass] = _applyDecs2203R(this, [], [dec]).c; - } - constructor() { - let foo = super(); - } - static { - _initClass(); - } -} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-accessor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-accessor/output.js deleted file mode 100644 index 896e644390b5..000000000000 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-accessor/output.js +++ /dev/null @@ -1,16 +0,0 @@ -var _call_x, _initProto; -const dec = () => { }; -class Foo extends Bar { - static { - [_call_x, _initProto] = _applyDecs2203R(this, [[dec, 3, "x", function () { - return Bar.prototype.foo.call(this); - }]], []).e; - } - constructor(...args) { - super(...args); - _initProto(this); - } - get #x() { - return _call_x(this); - } -} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-method/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-method/output.js deleted file mode 100644 index fab398c2f110..000000000000 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-method/output.js +++ /dev/null @@ -1,14 +0,0 @@ -var _call_x, _initProto; -const dec = () => { }; -class Foo extends Bar { - static { - [_call_x, _initProto] = _applyDecs2203R(this, [[dec, 2, "x", function () { - return Bar.prototype.foo.call(this); - }]], []).e; - } - constructor(...args) { - super(...args); - _initProto(this); - } - #x = _call_x; -} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/private/output.js index 21a4d803d1e4..baf22c626ff0 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/private/output.js @@ -1,4 +1,4 @@ -var _init_a, _get___a, _set___a, _init_b, _get___b, _set___b, _initProto; +var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto; const dec = ()=>{}; var ___a_1 = /*#__PURE__*/ new WeakMap(), _a = /*#__PURE__*/ new WeakMap(), ___b_2 = /*#__PURE__*/ new WeakMap(), _b = /*#__PURE__*/ new WeakMap(); class Foo { @@ -45,15 +45,42 @@ class Foo { } ] ], [])); +var __ = { + writable: true, + value: [_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 1, + "a", + function() { + return _class_private_field_get(this, ___a_1); + }, + function(_v) { + _class_private_field_set(this, ___a_1, _v); + } + ], + [ + dec, + 1, + "b", + function() { + return _class_private_field_get(this, ___b_2); + }, + function(_v) { + _class_private_field_set(this, ___b_2, _v); + } + ] + ], []).e +}; function get_a() { - return _get___a(this); + return _get_a(this); } function set_a(_v) { - _set___a(this, _v); + _set_a(this, _v); } function get_b() { - return _get___b(this); + return _get_b(this); } function set_b(_v) { - _set___b(this, _v); + _set_b(this, _v); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/public/output.js index 715a41222e22..c4f221381469 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/public/output.js @@ -1,37 +1,35 @@ -var _init_a, _init_b, _computedKey, _init_computedKey, _initProto; +var _init_a, _init_b, _init_computedKey, _initProto; const dec = ()=>{}; -_computedKey = 'c'; -var ____private_a_1 = /*#__PURE__*/ new WeakMap(), ____private_b_2 = /*#__PURE__*/ new WeakMap(), ____private_computedKey_3 = /*#__PURE__*/ new WeakMap(); -let _computedKey1 = _computedKey, _computedKey2 = _computedKey; +var __private_a_1 = /*#__PURE__*/ new WeakMap(), __private_b_2 = /*#__PURE__*/ new WeakMap(), __private_computedKey_3 = /*#__PURE__*/ new WeakMap(); class Foo { get a() { - return _class_private_field_get(this, ____private_a_1); + return _class_private_field_get(this, __private_a_1); } set a(_v) { - _class_private_field_set(this, ____private_a_1, _v); + _class_private_field_set(this, __private_a_1, _v); } get b() { - return _class_private_field_get(this, ____private_b_2); + return _class_private_field_get(this, __private_b_2); } set b(_v) { - _class_private_field_set(this, ____private_b_2, _v); + _class_private_field_set(this, __private_b_2, _v); } - get [_computedKey1]() { - return _class_private_field_get(this, ____private_computedKey_3); + get ['c']() { + return _class_private_field_get(this, __private_computedKey_3); } - set [_computedKey2](_v) { - _class_private_field_set(this, ____private_computedKey_3, _v); + set ['c'](_v) { + _class_private_field_set(this, __private_computedKey_3, _v); } constructor(){ - _class_private_field_init(this, ____private_a_1, { + _class_private_field_init(this, __private_a_1, { writable: true, value: (_initProto(this), _init_a(this)) }); - _class_private_field_init(this, ____private_b_2, { + _class_private_field_init(this, __private_b_2, { writable: true, value: _init_b(this, 123) }); - _class_private_field_init(this, ____private_computedKey_3, { + _class_private_field_init(this, __private_computedKey_3, { writable: true, value: _init_computedKey(this, 456) }); @@ -54,3 +52,23 @@ class Foo { _computedKey ] ], [])); +var __ = { + writable: true, + value: [_init_a, _init_b, _init_computedKey, _initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 1, + "a" + ], + [ + dec, + 1, + "b" + ], + [ + dec, + 1, + 'c' + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/static-private/output.js index c75fdb1cda5c..3db50cbd4b3e 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/static-private/output.js @@ -1,4 +1,4 @@ -var _init_a, _get___a, _set___a, _init_b, _get___b, _set___b, _initStatic; +var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initStatic; const dec = ()=>{}; class Foo { } @@ -37,6 +37,36 @@ var _b = { ], [])); _initStatic(Foo); })(); +var __ = { + writable: true, + value: (()=>{ + [_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 6, + "a", + function() { + return _class_static_private_field_spec_get(this, Foo, ___a_1); + }, + function(_v) { + _class_static_private_field_spec_set(this, Foo, ___a_1, _v); + } + ], + [ + dec, + 6, + "b", + function() { + return _class_static_private_field_spec_get(this, Foo, ___b_2); + }, + function(_v) { + _class_static_private_field_spec_set(this, Foo, ___b_2, _v); + } + ] + ], []).e; + _initStatic(Foo); + })() +}; var ___a_1 = { writable: true, value: _init_a(Foo) @@ -46,14 +76,14 @@ var ___b_2 = { value: _init_b(Foo, 123) }; function get_a() { - return _get___a(this); + return _get_a(this); } function set_a(_v) { - _set___a(this, _v); + _set_a(this, _v); } function get_b() { - return _get___b(this); + return _get_b(this); } function set_b(_v) { - _set___b(this, _v); + _set_b(this, _v); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/static-public/output.js index d18516ab1ffd..c7c45dd5c119 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/static-public/output.js @@ -1,25 +1,23 @@ -var _init_a, _init_b, _computedKey, _init_computedKey, _initStatic; +var _init_a, _init_b, _init_computedKey, _initStatic; const dec = ()=>{}; -_computedKey = 'c'; -let _computedKey1 = _computedKey, _computedKey2 = _computedKey; class Foo { static get a() { - return _class_static_private_field_spec_get(this, Foo, ____private_a_1); + return _class_static_private_field_spec_get(this, Foo, __private_a_1); } static set a(_v) { - _class_static_private_field_spec_set(this, Foo, ____private_a_1, _v); + _class_static_private_field_spec_set(this, Foo, __private_a_1, _v); } static get b() { - return _class_static_private_field_spec_get(this, Foo, ____private_b_2); + return _class_static_private_field_spec_get(this, Foo, __private_b_2); } static set b(_v) { - _class_static_private_field_spec_set(this, Foo, ____private_b_2, _v); + _class_static_private_field_spec_set(this, Foo, __private_b_2, _v); } - static get [_computedKey1]() { - return _class_static_private_field_spec_get(this, Foo, ____private_computedKey_3); + static get ['c']() { + return _class_static_private_field_spec_get(this, Foo, __private_computedKey_3); } - static set [_computedKey2](_v) { - _class_static_private_field_spec_set(this, Foo, ____private_computedKey_3, _v); + static set ['c'](_v) { + _class_static_private_field_spec_set(this, Foo, __private_computedKey_3, _v); } } (()=>{ @@ -43,14 +41,38 @@ class Foo { _initStatic(Foo); })(); var ____private_a_1 = { +var __ = { + writable: true, + value: (()=>{ + [_init_a, _init_b, _init_computedKey, _initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 6, + "a" + ], + [ + dec, + 6, + "b" + ], + [ + dec, + 6, + 'c' + ] + ], []).e; + _initStatic(Foo); + })() +}; +var __private_a_1 = { writable: true, value: _init_a(Foo) }; -var ____private_b_2 = { +var __private_b_2 = { writable: true, value: _init_b(Foo, 123) }; -var ____private_computedKey_3 = { +var __private_computedKey_3 = { writable: true, value: _init_computedKey(Foo, 456) }; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/undecorated-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/undecorated-public/output.js index 48be83643e9d..20cbebd349b7 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/undecorated-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/undecorated-public/output.js @@ -1,37 +1,34 @@ -var _computedKey; const dec = ()=>{}; -_computedKey = 'c'; -var ____private_a_1 = /*#__PURE__*/ new WeakMap(), ____private_b_2 = /*#__PURE__*/ new WeakMap(), ____private_computedKey_3 = /*#__PURE__*/ new WeakMap(); -let _computedKey1 = _computedKey, _computedKey2 = _computedKey; +var __private_a_1 = /*#__PURE__*/ new WeakMap(), __private_b_2 = /*#__PURE__*/ new WeakMap(), __private_computedKey_3 = /*#__PURE__*/ new WeakMap(); class Foo { get a() { - return _class_private_field_get(this, ____private_a_1); + return _class_private_field_get(this, __private_a_1); } set a(_v) { - _class_private_field_set(this, ____private_a_1, _v); + _class_private_field_set(this, __private_a_1, _v); } get b() { - return _class_private_field_get(this, ____private_b_2); + return _class_private_field_get(this, __private_b_2); } set b(_v) { - _class_private_field_set(this, ____private_b_2, _v); + _class_private_field_set(this, __private_b_2, _v); } - get [_computedKey1]() { - return _class_private_field_get(this, ____private_computedKey_3); + get ['c']() { + return _class_private_field_get(this, __private_computedKey_3); } - set [_computedKey2](_v) { - _class_private_field_set(this, ____private_computedKey_3, _v); + set ['c'](_v) { + _class_private_field_set(this, __private_computedKey_3, _v); } constructor(){ - _class_private_field_init(this, ____private_a_1, { + _class_private_field_init(this, __private_a_1, { writable: true, value: void 0 }); - _class_private_field_init(this, ____private_b_2, { + _class_private_field_init(this, __private_b_2, { writable: true, value: 123 }); - _class_private_field_init(this, ____private_computedKey_3, { + _class_private_field_init(this, __private_computedKey_3, { writable: true, value: 456 }); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/undecorated-static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/undecorated-static-public/output.js index 20ae182b3e20..777feb052aa0 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/undecorated-static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors--to-es2015/undecorated-static-public/output.js @@ -1,36 +1,33 @@ -var _computedKey; const dec = ()=>{}; -_computedKey = 'c'; -let _computedKey1 = _computedKey, _computedKey2 = _computedKey; class Foo { static get a() { - return _class_static_private_field_spec_get(this, Foo, ____private_a_1); + return _class_static_private_field_spec_get(this, Foo, __private_a_1); } static set a(_v) { - _class_static_private_field_spec_set(this, Foo, ____private_a_1, _v); + _class_static_private_field_spec_set(this, Foo, __private_a_1, _v); } static get b() { - return _class_static_private_field_spec_get(this, Foo, ____private_b_2); + return _class_static_private_field_spec_get(this, Foo, __private_b_2); } static set b(_v) { - _class_static_private_field_spec_set(this, Foo, ____private_b_2, _v); + _class_static_private_field_spec_set(this, Foo, __private_b_2, _v); } - static get [_computedKey1]() { - return _class_static_private_field_spec_get(this, Foo, ____private_computedKey_3); + static get ['c']() { + return _class_static_private_field_spec_get(this, Foo, __private_computedKey_3); } - static set [_computedKey2](_v) { - _class_static_private_field_spec_set(this, Foo, ____private_computedKey_3, _v); + static set ['c'](_v) { + _class_static_private_field_spec_set(this, Foo, __private_computedKey_3, _v); } } -var ____private_a_1 = { +var __private_a_1 = { writable: true, value: void 0 }; -var ____private_b_2 = { +var __private_b_2 = { writable: true, value: 123 }; -var ____private_computedKey_3 = { +var __private_computedKey_3 = { writable: true, value: 456 }; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/private/output.js index 83f084173968..b252949663c0 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/private/output.js @@ -1,8 +1,8 @@ -var _init_a, _get___a, _set___a, _init_b, _get___b, _set___b, _initProto; +var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_init_a, _get___a, _set___a, _init_b, _get___b, _set___b, _initProto] } = _apply_decs_2203_r(this, [ + [_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto] = _apply_decs_2203_r(this, [ [ dec, 1, @@ -25,20 +25,20 @@ class Foo { this.#__b_2 = _v; } ] - ], [])); + ], []).e; } #__a_1 = (_initProto(this), _init_a(this)); get #a() { - return _get___a(this); + return _get_a(this); } set #a(_v) { - _set___a(this, _v); + _set_a(this, _v); } #__b_2 = _init_b(this, 123); get #b() { - return _get___b(this); + return _get_b(this); } set #b(_v) { - _set___b(this, _v); + _set_b(this, _v); } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/public/output.js index 190af7b02435..aa04f5c31930 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/public/output.js @@ -1,9 +1,8 @@ -var _init_a, _init_b, _computedKey, _init_computedKey, _initProto; +var _init_a, _init_b, _init_computedKey, _initProto; const dec = ()=>{}; -_computedKey = 'c'; class Foo { static{ - ({ e: [_init_a, _init_b, _init_computedKey, _initProto] } = _apply_decs_2203_r(this, [ + [_init_a, _init_b, _init_computedKey, _initProto] = _apply_decs_2203_r(this, [ [ dec, 1, @@ -17,29 +16,29 @@ class Foo { [ dec, 1, - _computedKey + 'c' ] - ], [])); + ], []).e; } - #___private_a_1 = (_initProto(this), _init_a(this)); + #_private_a_1 = (_initProto(this), _init_a(this)); get a() { - return this.#___private_a_1; + return this.#_private_a_1; } set a(_v) { - this.#___private_a_1 = _v; + this.#_private_a_1 = _v; } - #___private_b_2 = _init_b(this, 123); + #_private_b_2 = _init_b(this, 123); get b() { - return this.#___private_b_2; + return this.#_private_b_2; } set b(_v) { - this.#___private_b_2 = _v; + this.#_private_b_2 = _v; } - #___private_computedKey_3 = _init_computedKey(this, 456); - get [_computedKey]() { - return this.#___private_computedKey_3; + #_private_computedKey_3 = _init_computedKey(this, 456); + get ['c']() { + return this.#_private_computedKey_3; } - set [_computedKey](_v) { - this.#___private_computedKey_3 = _v; + set ['c'](_v) { + this.#_private_computedKey_3 = _v; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/static-private/output.js index 539ca78fa5df..5378430fcfca 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/static-private/output.js @@ -1,8 +1,8 @@ -var _init_a, _get___a, _set___a, _init_b, _get___b, _set___b, _initStatic; +var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initStatic; const dec = ()=>{}; class Foo { static{ - ({ e: [_init_a, _get___a, _set___a, _init_b, _get___b, _set___b, _initStatic] } = _apply_decs_2203_r(this, [ + [_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initStatic] = _apply_decs_2203_r(this, [ [ dec, 6, @@ -25,21 +25,21 @@ class Foo { this.#__b_2 = _v; } ] - ], [])); + ], []).e; _initStatic(this); } static #__a_1 = _init_a(this); static get #a() { - return _get___a(this); + return _get_a(this); } static set #a(_v) { - _set___a(this, _v); + _set_a(this, _v); } static #__b_2 = _init_b(this, 123); static get #b() { - return _get___b(this); + return _get_b(this); } static set #b(_v) { - _set___b(this, _v); + _set_b(this, _v); } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/static-public/output.js index 9a86c0de98a4..99f5552aedc5 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/static-public/output.js @@ -1,9 +1,8 @@ -var _init_a, _init_b, _computedKey, _init_computedKey, _initStatic; +var _init_a, _init_b, _init_computedKey, _initStatic; const dec = ()=>{}; -_computedKey = 'c'; class Foo { static{ - ({ e: [_init_a, _init_b, _init_computedKey, _initStatic] } = _apply_decs_2203_r(this, [ + [_init_a, _init_b, _init_computedKey, _initStatic] = _apply_decs_2203_r(this, [ [ dec, 6, @@ -17,30 +16,30 @@ class Foo { [ dec, 6, - _computedKey + 'c' ] - ], [])); + ], []).e; _initStatic(this); } - static #___private_a_1 = _init_a(this); + static #_private_a_1 = _init_a(this); static get a() { - return this.#___private_a_1; + return this.#_private_a_1; } static set a(_v) { - this.#___private_a_1 = _v; + this.#_private_a_1 = _v; } - static #___private_b_2 = _init_b(this, 123); + static #_private_b_2 = _init_b(this, 123); static get b() { - return this.#___private_b_2; + return this.#_private_b_2; } static set b(_v) { - this.#___private_b_2 = _v; + this.#_private_b_2 = _v; } - static #___private_computedKey_3 = _init_computedKey(this, 456); - static get [_computedKey]() { - return this.#___private_computedKey_3; + static #_private_computedKey_3 = _init_computedKey(this, 456); + static get ['c']() { + return this.#_private_computedKey_3; } - static set [_computedKey](_v) { - this.#___private_computedKey_3 = _v; + static set ['c'](_v) { + this.#_private_computedKey_3 = _v; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/undecorated-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/undecorated-public/output.js index 36aa103b4504..1922b5fbe3fa 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/undecorated-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/undecorated-public/output.js @@ -1,26 +1,24 @@ -var _computedKey; const dec = ()=>{}; -_computedKey = 'c'; class Foo { - #___private_a_1; + #_private_a_1; get a() { - return this.#___private_a_1; + return this.#_private_a_1; } set a(_v) { - this.#___private_a_1 = _v; + this.#_private_a_1 = _v; } - #___private_b_2 = 123; + #_private_b_2 = 123; get b() { - return this.#___private_b_2; + return this.#_private_b_2; } set b(_v) { - this.#___private_b_2 = _v; + this.#_private_b_2 = _v; } - #___private_computedKey_3 = 456; - get [_computedKey]() { - return this.#___private_computedKey_3; + #_private_computedKey_3 = 456; + get ['c']() { + return this.#_private_computedKey_3; } - set [_computedKey](_v) { - this.#___private_computedKey_3 = _v; + set ['c'](_v) { + this.#_private_computedKey_3 = _v; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/undecorated-static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/undecorated-static-public/output.js index d7c92f4eea05..eea206d3a54d 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/undecorated-static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-accessors/undecorated-static-public/output.js @@ -1,26 +1,24 @@ -var _computedKey; const dec = ()=>{}; -_computedKey = 'c'; class Foo { - static #___private_a_1; + static #_private_a_1; static get a() { - return this.#___private_a_1; + return this.#_private_a_1; } static set a(_v) { - this.#___private_a_1 = _v; + this.#_private_a_1 = _v; } - static #___private_b_2 = 123; + static #_private_b_2 = 123; static get b() { - return this.#___private_b_2; + return this.#_private_b_2; } static set b(_v) { - this.#___private_b_2 = _v; + this.#_private_b_2 = _v; } - static #___private_computedKey_3 = 456; - static get [_computedKey]() { - return this.#___private_computedKey_3; + static #_private_computedKey_3 = 456; + static get ['c']() { + return this.#_private_computedKey_3; } - static set [_computedKey](_v) { - this.#___private_computedKey_3 = _v; + static set ['c'](_v) { + this.#_private_computedKey_3 = _v; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js index e4c767613c34..bd0cf59eed3a 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js @@ -35,6 +35,87 @@ const J = ((_K = class K extends (_L = L) { }, { c: [_K1, _initClass7] } = _apply_decs_2203_r(_K, [], [ dec ], _L), _initClass7(), _K), _K1); +}, __ = { + writable: true, + value: [_A1, _initClass] = _apply_decs_2203_r(_A, [], [ + dec + ]).c +}, __2 = { + writable: true, + value: _initClass() +}, _A), _A1); +const B = ((_C = class C { +}, __1 = { + writable: true, + value: [_C1, _initClass1] = _apply_decs_2203_r(_C, [], [ + dec + ]).c +}, __21 = { + writable: true, + value: _initClass1() +}, _C), _C1); +const D = ((_class = class { +}, __3 = { + writable: true, + value: [_class4, _initClass2] = _apply_decs_2203_r(_class, [], [ + dec + ]).c +}, __22 = { + writable: true, + value: _initClass2() +}, _class), _class4); +const E = (((_class1 = class { +}, __4 = { + writable: true, + value: [_class5, _initClass3] = _apply_decs_2203_r(_class1, [], [ + dec + ]).c +}, __23 = { + writable: true, + value: _initClass3() +}, _class1), _class5), 123); +const F = [ + ((_G = class G { + }, __5 = { + writable: true, + value: [_G1, _initClass4] = _apply_decs_2203_r(_G, [], [ + dec + ]).c + }, __24 = { + writable: true, + value: _initClass4() + }, _G), _G1), + ((_class2 = class { + }, __6 = { + writable: true, + value: [_class6, _initClass5] = _apply_decs_2203_r(_class2, [], [ + dec + ]).c + }, __25 = { + writable: true, + value: _initClass5() + }, _class2), _class6) +]; +const H = ((_class3 = class extends (_I = I) { +}, __7 = { + writable: true, + value: [_class7, _initClass6] = _apply_decs_2203_r(_class3, [], [ + dec + ]).c +}, __26 = { + writable: true, + value: _initClass6() +}, _class3), _class7); +const J = ((_K = class K extends (_L = L) { +}, __8 = { + writable: true, + value: [_K1, _initClass7] = _apply_decs_2203_r(_K, [], [ + dec + ]).c +}, __27 = { + writable: true, + value: _initClass7() +}, _K), _K1); function classFactory() { var _class; var _initClass, _class1; @@ -42,4 +123,13 @@ function classFactory() { }, { c: [_class1, _initClass] } = _apply_decs_2203_r(_class, [], [ dec ]), _initClass(), _class, _class1; + }, __ = { + writable: true, + value: [_class1, _initClass] = _apply_decs_2203_r(_class, [], [ + dec + ]).c + }, __2 = { + writable: true, + value: _initClass() + }, _class, _class1; } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js index e4c767613c34..bd0cf59eed3a 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js @@ -35,6 +35,87 @@ const J = ((_K = class K extends (_L = L) { }, { c: [_K1, _initClass7] } = _apply_decs_2203_r(_K, [], [ dec ], _L), _initClass7(), _K), _K1); +}, __ = { + writable: true, + value: [_A1, _initClass] = _apply_decs_2203_r(_A, [], [ + dec + ]).c +}, __2 = { + writable: true, + value: _initClass() +}, _A), _A1); +const B = ((_C = class C { +}, __1 = { + writable: true, + value: [_C1, _initClass1] = _apply_decs_2203_r(_C, [], [ + dec + ]).c +}, __21 = { + writable: true, + value: _initClass1() +}, _C), _C1); +const D = ((_class = class { +}, __3 = { + writable: true, + value: [_class4, _initClass2] = _apply_decs_2203_r(_class, [], [ + dec + ]).c +}, __22 = { + writable: true, + value: _initClass2() +}, _class), _class4); +const E = (((_class1 = class { +}, __4 = { + writable: true, + value: [_class5, _initClass3] = _apply_decs_2203_r(_class1, [], [ + dec + ]).c +}, __23 = { + writable: true, + value: _initClass3() +}, _class1), _class5), 123); +const F = [ + ((_G = class G { + }, __5 = { + writable: true, + value: [_G1, _initClass4] = _apply_decs_2203_r(_G, [], [ + dec + ]).c + }, __24 = { + writable: true, + value: _initClass4() + }, _G), _G1), + ((_class2 = class { + }, __6 = { + writable: true, + value: [_class6, _initClass5] = _apply_decs_2203_r(_class2, [], [ + dec + ]).c + }, __25 = { + writable: true, + value: _initClass5() + }, _class2), _class6) +]; +const H = ((_class3 = class extends (_I = I) { +}, __7 = { + writable: true, + value: [_class7, _initClass6] = _apply_decs_2203_r(_class3, [], [ + dec + ]).c +}, __26 = { + writable: true, + value: _initClass6() +}, _class3), _class7); +const J = ((_K = class K extends (_L = L) { +}, __8 = { + writable: true, + value: [_K1, _initClass7] = _apply_decs_2203_r(_K, [], [ + dec + ]).c +}, __27 = { + writable: true, + value: _initClass7() +}, _K), _K1); function classFactory() { var _class; var _initClass, _class1; @@ -42,4 +123,13 @@ function classFactory() { }, { c: [_class1, _initClass] } = _apply_decs_2203_r(_class, [], [ dec ]), _initClass(), _class, _class1; + }, __ = { + writable: true, + value: [_class1, _initClass] = _apply_decs_2203_r(_class, [], [ + dec + ]).c + }, __2 = { + writable: true, + value: _initClass() + }, _class, _class1; } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js index 88fffde6c675..8f96d24a104e 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js @@ -15,3 +15,26 @@ class Foo extends (_Bar = _Bar1) { dec2 ], _Bar)); _initClass1(); +var __ = { + writable: true, + value: [_Bar1, _initClass] = _apply_decs_2203_r(Bar, [], [ + dec1 + ]).c +}; +var __2 = { + writable: true, + value: _initClass() +}; +let _Foo; +class Foo extends (_Bar = _Bar1) { +} +var __1 = { + writable: true, + value: [_Foo, _initClass1] = _apply_decs_2203_r(Foo, [], [ + dec2 + ]).c +}; +var __21 = { + writable: true, + value: _initClass1() +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js index 9a68040fa982..aa6f5a401bae 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js @@ -14,6 +14,20 @@ new (_class = class extends _identity { ])); _define_property(Foo, "field", 123); })(), _class)(); +}, __ = { + writable: true, + value: (()=>{ + class Foo { + } + var __ = { + writable: true, + value: [_Foo1, _initClass] = _apply_decs_2203_r(Foo, [], [ + dec + ]).c + }; + _define_property(Foo, "field", 123); + })() +}, _class)(); let _Bar; new (_class1 = class extends _identity { constructor(){ @@ -30,3 +44,20 @@ new (_class1 = class extends _identity { Bar.otherField = 456; })(), 123)); })(), _class1)(); +}, __1 = { + writable: true, + value: (()=>{ + var _ref; + class Bar extends (_ref = _Foo = _Foo1) { + } + var __ = { + writable: true, + value: [_Bar, _initClass1] = _apply_decs_2203_r(Bar, [], [ + dec + ]).c + }; + _define_property(Bar, "field", ((()=>{ + Bar.otherField = 456; + })(), 123)); + })() +}, _class1)(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/replacement-with-expr/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/replacement-with-expr/output.js index 48e8721628fe..f182b7515b32 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/replacement-with-expr/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/replacement-with-expr/output.js @@ -8,4 +8,13 @@ const Foo = ((_Bar = class Bar { }, { c: [_Bar1, _initClass] } = _apply_decs_2203_r(_Bar, [], [ dec ]), _initClass(), _Bar), _Bar1); +}, __ = { + writable: true, + value: [_Bar1, _initClass] = _apply_decs_2203_r(_Bar, [], [ + dec + ]).c +}, __2 = { + writable: true, + value: _initClass() +}, _Bar), _Bar1); const foo = new Foo(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/replacement/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/replacement/output.js index 9664a4b041e1..0206d6ecb8e4 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/replacement/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/replacement/output.js @@ -14,4 +14,18 @@ new (_class = class extends _identity { ])); _define_property(Foo, "foo", new _Foo()); })(), _class)(); +}, __ = { + writable: true, + value: (()=>{ + class Foo { + } + var __ = { + writable: true, + value: [_Foo, _initClass] = _apply_decs_2203_r(Foo, [], [ + dec + ]).c + }; + _define_property(Foo, "foo", new _Foo()); + })() +}, _class)(); const foo = new _Foo(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js index 1e5b39d65199..9fc471b8ecf5 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js @@ -2,9 +2,9 @@ var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, const dec = ()=>{}; const A = (class A { static{ - ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [ + [_A, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{} static{ @@ -13,9 +13,9 @@ const A = (class A { }, _A); const B = (class C { static{ - ({ c: [_C, _initClass1] } = _apply_decs_2203_r(this, [], [ + [_C, _initClass1] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{} static{ @@ -24,9 +24,9 @@ const B = (class C { }, _C); const D = (class { static{ - ({ c: [_class, _initClass2] } = _apply_decs_2203_r(this, [], [ + [_class, _initClass2] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{} static{ @@ -35,9 +35,9 @@ const D = (class { }, _class); const E = ((class { static{ - ({ c: [_class1, _initClass3] } = _apply_decs_2203_r(this, [], [ + [_class1, _initClass3] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{} static{ @@ -47,9 +47,9 @@ const E = ((class { const F = [ (class G { static{ - ({ c: [_G, _initClass4] } = _apply_decs_2203_r(this, [], [ + [_G, _initClass4] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{} static{ @@ -58,9 +58,9 @@ const F = [ }, _G), (class { static{ - ({ c: [_class2, _initClass5] } = _apply_decs_2203_r(this, [], [ + [_class2, _initClass5] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{} static{ @@ -70,9 +70,9 @@ const F = [ ]; const H = (class extends (_I = I) { static{ - ({ c: [_class3, _initClass6] } = _apply_decs_2203_r(this, [], [ + [_class3, _initClass6] = _apply_decs_2203_r(this, [], [ dec - ], _I)); + ]).c; } static{} static{ @@ -81,9 +81,9 @@ const H = (class extends (_I = I) { }, _class3); const J = (class K extends (_L = L) { static{ - ({ c: [_K, _initClass7] } = _apply_decs_2203_r(this, [], [ + [_K, _initClass7] = _apply_decs_2203_r(this, [], [ dec - ], _L)); + ]).c; } static{} static{ @@ -94,9 +94,9 @@ function classFactory() { var _initClass, _class; return class { static{ - ({ c: [_class, _initClass] } = _apply_decs_2203_r(this, [], [ + [_class, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{} static{ diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js index 7e7ad3889016..423f1f606d9f 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js @@ -2,9 +2,9 @@ var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, const dec = ()=>{}; const A = (class A { static{ - ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [ + [_A, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{ _initClass(); @@ -12,9 +12,9 @@ const A = (class A { }, _A); const B = (class C { static{ - ({ c: [_C, _initClass1] } = _apply_decs_2203_r(this, [], [ + [_C, _initClass1] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{ _initClass1(); @@ -22,9 +22,9 @@ const B = (class C { }, _C); const D = (class { static{ - ({ c: [_class, _initClass2] } = _apply_decs_2203_r(this, [], [ + [_class, _initClass2] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{ _initClass2(); @@ -32,9 +32,9 @@ const D = (class { }, _class); const E = ((class { static{ - ({ c: [_class1, _initClass3] } = _apply_decs_2203_r(this, [], [ + [_class1, _initClass3] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{ _initClass3(); @@ -43,9 +43,9 @@ const E = ((class { const F = [ (class G { static{ - ({ c: [_G, _initClass4] } = _apply_decs_2203_r(this, [], [ + [_G, _initClass4] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{ _initClass4(); @@ -53,9 +53,9 @@ const F = [ }, _G), (class { static{ - ({ c: [_class2, _initClass5] } = _apply_decs_2203_r(this, [], [ + [_class2, _initClass5] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{ _initClass5(); @@ -64,9 +64,9 @@ const F = [ ]; const H = (class extends (_I = I) { static{ - ({ c: [_class3, _initClass6] } = _apply_decs_2203_r(this, [], [ + [_class3, _initClass6] = _apply_decs_2203_r(this, [], [ dec - ], _I)); + ]).c; } static{ _initClass6(); @@ -74,9 +74,9 @@ const H = (class extends (_I = I) { }, _class3); const J = (class K extends (_L = L) { static{ - ({ c: [_K, _initClass7] } = _apply_decs_2203_r(this, [], [ + [_K, _initClass7] = _apply_decs_2203_r(this, [], [ dec - ], _L)); + ]).c; } static{ _initClass7(); @@ -86,9 +86,9 @@ function classFactory() { var _initClass, _class; return class { static{ - ({ c: [_class, _initClass] } = _apply_decs_2203_r(this, [], [ + [_class, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{ _initClass(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js index 4cc40167c6c8..7f21ab9ea318 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js @@ -3,9 +3,9 @@ const dec = ()=>{}; let _Bar1; class Bar { static{ - ({ c: [_Bar1, _initClass] } = _apply_decs_2203_r(this, [], [ + [_Bar1, _initClass] = _apply_decs_2203_r(this, [], [ dec1 - ])); + ]).c; } static{ _initClass(); @@ -14,9 +14,9 @@ class Bar { let _Foo; class Foo extends (_Bar = _Bar1) { static{ - ({ c: [_Foo, _initClass1] } = _apply_decs_2203_r(this, [], [ + [_Foo, _initClass1] = _apply_decs_2203_r(this, [], [ dec2 - ], _Bar)); + ]).c; } static{ _initClass1(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js index 772fbce84650..d23296afd497 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js @@ -8,9 +8,9 @@ new class extends _identity { static{ class Foo { static{ - ({ c: [_Foo1, _initClass] } = _apply_decs_2203_r(this, [], [ + [_Foo1, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static field = 123; } @@ -24,9 +24,9 @@ new class extends _identity { static{ class Bar extends (_Foo = _Foo1) { static{ - ({ c: [_Bar, _initClass1] } = _apply_decs_2203_r(this, [], [ + [_Bar, _initClass1] = _apply_decs_2203_r(this, [], [ dec - ], _Foo)); + ]).c; } static field = ((()=>{ this.otherField = 456; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-static-installed-on-correct-class/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-static-installed-on-correct-class/output.js index c14d798e64cf..ee3efb9e022e 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-static-installed-on-correct-class/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-static-installed-on-correct-class/output.js @@ -12,9 +12,9 @@ new class extends _identity { static{ class Foo { static{ - ({ c: [_Foo, _initClass] } = _apply_decs_2203_r(this, [], [ + [_Foo, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static x; static m() {} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-static-this/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-static-this/output.js index fb029ff2871f..7d561b9f6677 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-static-this/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-static-this/output.js @@ -10,9 +10,9 @@ new class extends _identity { static{ class Foo { static{ - ({ c: [_Foo, _initClass] } = _apply_decs_2203_r(this, [], [ + [_Foo, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static field = ((()=>{ this; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-with-expr/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-with-expr/output.js index 062adff4b2ba..87493c0e9de9 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-with-expr/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement-with-expr/output.js @@ -2,9 +2,9 @@ var _initClass, _Bar; const dec = ()=>{}; const Foo = (class Bar { static{ - ({ c: [_Bar, _initClass] } = _apply_decs_2203_r(this, [], [ + [_Bar, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } bar = new _Bar(); static{ diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement/output.js index 9e36574230fd..f02fa88edee9 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/replacement/output.js @@ -8,9 +8,9 @@ new class extends _identity { static{ class Foo { static{ - ({ c: [_Foo, _initClass] } = _apply_decs_2203_r(this, [], [ + [_Foo, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static foo = new _Foo(); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/computed-keys-same-ast/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/computed-keys-same-ast/output.js index 933db1d53079..967a943bf110 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/computed-keys-same-ast/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/computed-keys-same-ast/output.js @@ -25,3 +25,18 @@ class Foo { _computedKey1 ] ], [])); +var __ = { + writable: true, + value: [_initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 2, + _computedKey + ], + [ + dec, + 2, + _computedKey1 + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/computed-keys-same-value/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/computed-keys-same-value/output.js index dccc598fd150..511ec3a6d2ff 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/computed-keys-same-value/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/computed-keys-same-value/output.js @@ -25,3 +25,18 @@ class Foo { _computedKey1 ] ], [])); +var __ = { + writable: true, + value: [_initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 2, + _computedKey + ], + [ + dec, + 2, + _computedKey1 + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/methods-with-same-key/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/methods-with-same-key/output.js index 00f9a88ebbc2..1ea9e14a4efe 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/methods-with-same-key/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys--to-es2015/methods-with-same-key/output.js @@ -23,3 +23,18 @@ class Foo { "a" ] ], [])); +var __ = { + writable: true, + value: [_initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 2, + "a" + ], + [ + dec, + 2, + "a" + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/computed-keys-same-ast/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/computed-keys-same-ast/output.js index 2010b8586776..f1bcd561bc52 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/computed-keys-same-ast/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/computed-keys-same-ast/output.js @@ -3,7 +3,7 @@ const dec = ()=>{}; _computedKey = getKey(), _computedKey1 = getKey(); class Foo { static{ - ({ e: [_initProto] } = _apply_decs_2203_r(this, [ + [_initProto] = _apply_decs_2203_r(this, [ [ dec, 2, @@ -14,7 +14,7 @@ class Foo { 2, _computedKey1 ] - ], [])); + ], []).e; } constructor(){ _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/computed-keys-same-value/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/computed-keys-same-value/output.js index b84b1d94fc28..0875124fc1b4 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/computed-keys-same-value/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/computed-keys-same-value/output.js @@ -3,7 +3,7 @@ const dec = ()=>{}; _computedKey = getKeyI(), _computedKey1 = getKeyJ(); class Foo { static{ - ({ e: [_initProto] } = _apply_decs_2203_r(this, [ + [_initProto] = _apply_decs_2203_r(this, [ [ dec, 2, @@ -14,7 +14,7 @@ class Foo { 2, _computedKey1 ] - ], [])); + ], []).e; } constructor(){ _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/method-and-field/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/method-and-field/output.js index 7c5f45ec7e36..55f0a0552c2c 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/method-and-field/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/method-and-field/output.js @@ -3,6 +3,7 @@ const dec = ()=>{}; class Foo { static{ ({ e: [_init_a, _initProto] } = _apply_decs_2203_r(this, [ + [_init_a, _initProto] = _apply_decs_2203_r(this, [ [ dec, 2, @@ -13,7 +14,7 @@ class Foo { 0, "a" ] - ], [])); + ], []).e; } a = (_initProto(this), _init_a(this, 123)); a() { diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/methods-with-same-key/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/methods-with-same-key/output.js index 8721109e43a1..7485365e6d3c 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/methods-with-same-key/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/methods-with-same-key/output.js @@ -2,7 +2,7 @@ var _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_initProto] } = _apply_decs_2203_r(this, [ + [_initProto] = _apply_decs_2203_r(this, [ [ dec, 2, @@ -13,7 +13,7 @@ class Foo { 2, "a" ] - ], [])); + ], []).e; } constructor(){ _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-anonymous/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-anonymous/output.mjs index 1e195c59789c..06559147c2f3 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-anonymous/output.mjs +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-anonymous/output.mjs @@ -2,9 +2,9 @@ var _initClass; let _A; class A { static{ - ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [ + [_A, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{ _initClass(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-named/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-named/output.mjs index 47f8ce19f916..dcf45e6435af 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-named/output.mjs +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-named/output.mjs @@ -2,9 +2,9 @@ var _initClass; let __default; class _default { static{ - ({ c: [__default, _initClass] } = _apply_decs_2203_r(this, [], [ + [__default, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } static{ _initClass(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/member-decorator/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/member-decorator/output.mjs index 32ce221ec4d5..90fabe9a013d 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/member-decorator/output.mjs +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/member-decorator/output.mjs @@ -1,13 +1,13 @@ var _init_x; export class A { - static{ - ({ e: [_init_x] } = _apply_decs_2203_r(this, [ - [ - dec, - 0, - "x" - ] - ], [])); - } - x = _init_x(this); + static{ + [_init_x] = _apply_decs_2203_r(this, [ + [ + dec, + 0, + "x" + ] + ], []).e; + } + x = _init_x(this); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/named/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/named/output.mjs index cd7e9a5d0bf9..fc433f26f035 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/named/output.mjs +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/named/output.mjs @@ -1,12 +1,12 @@ var _initClass; let _A; class A { - static { - ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [ + static{ + [_A, _initClass] = _apply_decs_2203_r(this, [], [ dec - ])); + ]).c; } - static { + static{ _initClass(); } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/private/output.js index 2f6115b272b6..ccda14cf091c 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/private/output.js @@ -37,3 +37,30 @@ class Foo { } ] ], [])); +var __ = { + writable: true, + value: [_init_a, _init_b] = _apply_decs_2203_r(Foo, [ + [ + dec, + 0, + "a", + function() { + return _class_private_field_get(this, _a); + }, + function(value) { + _class_private_field_set(this, _a, value); + } + ], + [ + dec, + 0, + "b", + function() { + return _class_private_field_get(this, _b); + }, + function(value) { + _class_private_field_set(this, _b, value); + } + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/public/output.js index 5d97dc59b971..e9cbef111dd8 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/public/output.js @@ -1,12 +1,10 @@ -var _computedKey, _init_a, _init_b, _init__computedKey; +var _init_a, _init_b, _init_computedKey; const dec = ()=>{}; -_computedKey = 'c'; -let _computedKey1 = _computedKey; class Foo { constructor(){ _define_property(this, "a", _init_a(this)); _define_property(this, "b", _init_b(this, 123)); - _define_property(this, _computedKey1, _init__computedKey(this, 456)); + _define_property(this, 'c', _init_computedKey(this, 456)); } } ({ e: [_init_a, _init_b, _init__computedKey] } = _apply_decs_2203_r(Foo, [ @@ -26,3 +24,23 @@ class Foo { _computedKey ] ], [])); +var __ = { + writable: true, + value: [_init_a, _init_b, _init_computedKey] = _apply_decs_2203_r(Foo, [ + [ + dec, + 0, + "a" + ], + [ + dec, + 0, + "b" + ], + [ + dec, + 0, + 'c' + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-private/output.js index 325a7b990a13..bbcd77cfc2e9 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-private/output.js @@ -26,6 +26,33 @@ class Foo { } ] ], [])); +var __ = { + writable: true, + value: [_init_a, _init_b] = _apply_decs_2203_r(Foo, [ + [ + dec, + 5, + "a", + function() { + return _class_static_private_field_spec_get(this, Foo, _a); + }, + function(value) { + _class_static_private_field_spec_set(this, Foo, _a, value); + } + ], + [ + dec, + 5, + "b", + function() { + return _class_static_private_field_spec_get(this, Foo, _b); + }, + function(value) { + _class_static_private_field_spec_set(this, Foo, _b, value); + } + ] + ], []).e +}; var _a = { writable: true, value: _init_a(Foo) diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-public/output.js index 7642e44c3821..076ed794de9a 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-public/output.js @@ -1,6 +1,5 @@ -var _computedKey, _init_a, _init_b, _init__computedKey; +var _init_a, _init_b, _init_computedKey; const dec = ()=>{}; -_computedKey = 'c'; class Foo { } ({ e: [_init_a, _init_b, _init__computedKey] } = _apply_decs_2203_r(Foo, [ @@ -20,6 +19,26 @@ class Foo { _computedKey ] ], [])); +var __ = { + writable: true, + value: [_init_a, _init_b, _init_computedKey] = _apply_decs_2203_r(Foo, [ + [ + dec, + 5, + "a" + ], + [ + dec, + 5, + "b" + ], + [ + dec, + 5, + 'c' + ] + ], []).e +}; _define_property(Foo, "a", _init_a(Foo)); _define_property(Foo, "b", _init_b(Foo, 123)); -_define_property(Foo, _computedKey, _init__computedKey(Foo, 456)); +_define_property(Foo, 'c', _init_computedKey(Foo, 456)); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/private/output.js index 14a46595a464..9a5aef864522 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/private/output.js @@ -2,7 +2,7 @@ var _init_a, _init_b; const dec = ()=>{}; class Foo { static{ - ({ e: [_init_a, _init_b] } = _apply_decs_2203_r(this, [ + [_init_a, _init_b] = _apply_decs_2203_r(this, [ [ dec, 0, @@ -25,7 +25,7 @@ class Foo { this.#b = value; } ] - ], [])); + ], []).e; } #a = _init_a(this); #b = _init_b(this, 123); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/public/output.js index 240e1c9a8c35..b204a514dce5 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/public/output.js @@ -1,9 +1,8 @@ -var _computedKey, _init_a, _init_b, _init__computedKey; +var _init_a, _init_b, _init_computedKey; const dec = ()=>{}; -_computedKey = 'c'; class Foo { static{ - ({ e: [_init_a, _init_b, _init__computedKey] } = _apply_decs_2203_r(this, [ + [_init_a, _init_b, _init_computedKey] = _apply_decs_2203_r(this, [ [ dec, 0, @@ -17,11 +16,11 @@ class Foo { [ dec, 0, - _computedKey + 'c' ] - ], [])); + ], []).e; } a = _init_a(this); b = _init_b(this, 123); - [_computedKey] = _init__computedKey(this, 456); + ['c'] = _init_computedKey(this, 456); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/static-private/output.js index 17f50f428b63..31bd0d84cefc 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/static-private/output.js @@ -2,7 +2,7 @@ var _init_a, _init_b; const dec = ()=>{}; class Foo { static{ - ({ e: [_init_a, _init_b] } = _apply_decs_2203_r(this, [ + [_init_a, _init_b] = _apply_decs_2203_r(this, [ [ dec, 5, @@ -25,7 +25,7 @@ class Foo { this.#b = value; } ] - ], [])); + ], []).e; } static #a = _init_a(this); static #b = _init_b(this, 123); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/static-public/output.js index b9971aed4024..b0620c0c2a85 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields/static-public/output.js @@ -1,9 +1,8 @@ -var _computedKey, _init_a, _init_b, _init__computedKey; +var _init_a, _init_b, _init_computedKey; const dec = ()=>{}; -_computedKey = 'c'; class Foo { static{ - ({ e: [_init_a, _init_b, _init__computedKey] } = _apply_decs_2203_r(this, [ + [_init_a, _init_b, _init_computedKey] = _apply_decs_2203_r(this, [ [ dec, 5, @@ -17,11 +16,11 @@ class Foo { [ dec, 5, - _computedKey + 'c' ] - ], [])); + ], []).e; } static a = _init_a(this); static b = _init_b(this, 123); - static [_computedKey] = _init__computedKey(this, 456); + static ['c'] = _init_computedKey(this, 456); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/private/output.js index f3ceafa4db98..3cbe075f9463 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/private/output.js @@ -23,6 +23,19 @@ class Foo { } ] ], [])); +var __ = { + writable: true, + value: [_call_a, _initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 3, + "a", + function() { + return this.value; + } + ] + ], []).e +}; function get_a() { return _call_a(this); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/public/output.js index 784fba5644f8..a3017067b205 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/public/output.js @@ -1,12 +1,10 @@ -var _computedKey, _initProto; +var _initProto; const dec = ()=>{}; -_computedKey = 'b'; -let _computedKey1 = _computedKey; class Foo { get a() { return this.value; } - get [_computedKey1]() { + get ['b']() { return this.value; } constructor(){ @@ -25,3 +23,18 @@ class Foo { _computedKey ] ], [])); +var __ = { + writable: true, + value: [_initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 3, + "a" + ], + [ + dec, + 3, + 'b' + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/static-private/output.js index 5a5d8ceaa9b0..dc2c8c7ff3d4 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/static-private/output.js @@ -22,6 +22,22 @@ var _a = { ], [])); _initStatic(Foo); })(); +var __ = { + writable: true, + value: (()=>{ + [_call_a, _initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 8, + "a", + function() { + return this.value; + } + ] + ], []).e; + _initStatic(Foo); + })() +}; _define_property(Foo, "value", 1); function get_a() { return _call_a(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/static-public/output.js index 3881d53e153c..be07311a7c42 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/static-public/output.js @@ -1,12 +1,10 @@ -var _computedKey, _initStatic; +var _initStatic; const dec = ()=>{}; -_computedKey = 'b'; -let _computedKey1 = _computedKey; class Foo { static get a() { return this.value; } - static get [_computedKey1]() { + static get ['b']() { return this.value; } } @@ -25,4 +23,22 @@ class Foo { ], [])); _initStatic(Foo); })(); +var __ = { + writable: true, + value: (()=>{ + [_initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 8, + "a" + ], + [ + dec, + 8, + 'b' + ] + ], []).e; + _initStatic(Foo); + })() +}; _define_property(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/private/output.js index 18a0d5dd0550..304250f3ed31 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/private/output.js @@ -34,6 +34,27 @@ class Foo { } ] ], [])); +var __ = { + writable: true, + value: [_call_a, _call_a1, _initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 3, + "a", + function() { + return this.value; + } + ], + [ + dec, + 4, + "a", + function(v) { + this.value = v; + } + ] + ], []).e +}; function get_a() { return _call_a(this); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/public/output.js index b70764d6f90c..538c885410ea 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/public/output.js @@ -1,7 +1,5 @@ -var _computedKey, _computedKey1, _initProto; +var _initProto; const dec = ()=>{}; -_computedKey = 'b', _computedKey1 = 'b'; -let _computedKey2 = _computedKey, _computedKey3 = _computedKey1; class Foo { get a() { return this.value; @@ -9,10 +7,10 @@ class Foo { set a(v) { this.value = v; } - get [_computedKey2]() { + get ['b']() { return this.value; } - set [_computedKey3](v) { + set ['b'](v) { this.value = v; } constructor(){ @@ -41,3 +39,28 @@ class Foo { _computedKey1 ] ], [])); +var __ = { + writable: true, + value: [_initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 3, + "a" + ], + [ + dec, + 4, + "a" + ], + [ + dec, + 3, + 'b' + ], + [ + dec, + 4, + 'b' + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/static-private/output.js index d8e9eb9200a7..70f7b43f2d13 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/static-private/output.js @@ -33,6 +33,30 @@ var _a = { ], [])); _initStatic(Foo); })(); +var __ = { + writable: true, + value: (()=>{ + [_call_a, _call_a1, _initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 8, + "a", + function() { + return this.value; + } + ], + [ + dec, + 9, + "a", + function(v) { + this.value = v; + } + ] + ], []).e; + _initStatic(Foo); + })() +}; _define_property(Foo, "value", 1); function get_a() { return _call_a(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/static-public/output.js index c6db811db8ab..c45fd076ecd5 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/static-public/output.js @@ -1,7 +1,5 @@ -var _computedKey, _computedKey1, _initStatic; +var _initStatic; const dec = ()=>{}; -_computedKey = 'b', _computedKey1 = 'b'; -let _computedKey2 = _computedKey, _computedKey3 = _computedKey1; class Foo { static get a() { return this.value; @@ -9,10 +7,10 @@ class Foo { static set a(v) { this.value = v; } - static get [_computedKey2]() { + static get ['b']() { return this.value; } - static set [_computedKey3](v) { + static set ['b'](v) { this.value = v; } } @@ -41,4 +39,32 @@ class Foo { ], [])); _initStatic(Foo); })(); +var __ = { + writable: true, + value: (()=>{ + [_initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 8, + "a" + ], + [ + dec, + 9, + "a" + ], + [ + dec, + 8, + 'b' + ], + [ + dec, + 9, + 'b' + ] + ], []).e; + _initStatic(Foo); + })() +}; _define_property(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/private/output.js index b4b55534ad67..5b39d91ad95b 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/private/output.js @@ -2,7 +2,7 @@ var _call_a, _call_a1, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_a, _call_a1, _initProto] } = _apply_decs_2203_r(this, [ + [_call_a, _call_a1, _initProto] = _apply_decs_2203_r(this, [ [ dec, 3, @@ -19,7 +19,7 @@ class Foo { this.value = v; } ] - ], [])); + ], []).e; } value = (_initProto(this), 1); get #a() { diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/public/output.js index f36175396d1c..482cb61c33ba 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/public/output.js @@ -1,9 +1,9 @@ -var _computedKey, _computedKey1, _initProto; +var _initProto; const dec = ()=>{}; -_computedKey = 'b', _computedKey1 = 'b'; class Foo { static{ ({ e: [_initProto] } = _apply_decs_2203_r(this, [ + [_initProto] = _apply_decs_2203_r(this, [ [ dec, 3, @@ -17,14 +17,14 @@ class Foo { [ dec, 3, - _computedKey + 'b' ], [ dec, 4, - _computedKey1 + 'b' ] - ], [])); + ], []).e; } value = (_initProto(this), 1); get a() { @@ -33,10 +33,10 @@ class Foo { set a(v) { this.value = v; } - get [_computedKey]() { + get ['b']() { return this.value; } - set [_computedKey1](v) { + set ['b'](v) { this.value = v; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/static-private/output.js index 33daccabcc78..a619e61b926e 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/static-private/output.js @@ -2,7 +2,7 @@ var _call_a, _call_a1, _initStatic; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_a, _call_a1, _initStatic] } = _apply_decs_2203_r(this, [ + [_call_a, _call_a1, _initStatic] = _apply_decs_2203_r(this, [ [ dec, 8, @@ -19,7 +19,7 @@ class Foo { this.value = v; } ] - ], [])); + ], []).e; _initStatic(this); } static value = 1; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/static-public/output.js index 1a79779138b9..cfdd9fd80675 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/static-public/output.js @@ -1,9 +1,8 @@ -var _computedKey, _computedKey1, _initStatic; +var _initStatic; const dec = ()=>{}; -_computedKey = 'b', _computedKey1 = 'b'; class Foo { static{ - ({ e: [_initStatic] } = _apply_decs_2203_r(this, [ + [_initStatic] = _apply_decs_2203_r(this, [ [ dec, 8, @@ -17,14 +16,14 @@ class Foo { [ dec, 8, - _computedKey + 'b' ], [ dec, 9, - _computedKey1 + 'b' ] - ], [])); + ], []).e; _initStatic(this); } static value = 1; @@ -34,10 +33,10 @@ class Foo { static set a(v) { this.value = v; } - static get [_computedKey]() { + static get ['b']() { return this.value; } - static set [_computedKey1](v) { + static set ['b'](v) { this.value = v; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/private/output.js index d6c081b17186..7c3c5d57e794 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/private/output.js @@ -3,6 +3,7 @@ const dec = ()=>{}; class Foo { static{ ({ e: [_call_a, _initProto] } = _apply_decs_2203_r(this, [ + [_call_a, _initProto] = _apply_decs_2203_r(this, [ [ dec, 3, @@ -11,7 +12,7 @@ class Foo { return this.value; } ] - ], [])); + ], []).e; } value = (_initProto(this), 1); get #a() { diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/public/output.js index 6465c1017e7b..41626f2b4112 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/public/output.js @@ -1,9 +1,9 @@ -var _computedKey, _initProto; +var _initProto; const dec = ()=>{}; -_computedKey = 'b'; class Foo { static{ ({ e: [_initProto] } = _apply_decs_2203_r(this, [ + [_initProto] = _apply_decs_2203_r(this, [ [ dec, 3, @@ -12,15 +12,15 @@ class Foo { [ dec, 3, - _computedKey + 'b' ] - ], [])); + ], []).e; } value = (_initProto(this), 1); get a() { return this.value; } - get [_computedKey]() { + get ['b']() { return this.value; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/static-private/output.js index 5bfbd8edcd8b..a4d0244004d0 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/static-private/output.js @@ -2,7 +2,7 @@ var _call_a, _initStatic; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_a, _initStatic] } = _apply_decs_2203_r(this, [ + [_call_a, _initStatic] = _apply_decs_2203_r(this, [ [ dec, 8, @@ -11,7 +11,7 @@ class Foo { return this.value; } ] - ], [])); + ], []).e; _initStatic(this); } static value = 1; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/static-public/output.js index 003cbfb13113..8895f1c0503e 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/static-public/output.js @@ -1,9 +1,8 @@ -var _computedKey, _initStatic; +var _initStatic; const dec = ()=>{}; -_computedKey = 'b'; class Foo { static{ - ({ e: [_initStatic] } = _apply_decs_2203_r(this, [ + [_initStatic] = _apply_decs_2203_r(this, [ [ dec, 8, @@ -12,16 +11,16 @@ class Foo { [ dec, 8, - _computedKey + 'b' ] - ], [])); + ], []).e; _initStatic(this); } static value = 1; static get a() { return this.value; } - static get [_computedKey]() { + static get ['b']() { return this.value; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/private/output.js index 6d64f8737fea..107485993fe4 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/private/output.js @@ -23,6 +23,19 @@ class Foo { } ] ], [])); +var __ = { + writable: true, + value: [_call_a, _initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 2, + "a", + function() { + return this.value; + } + ] + ], []).e +}; function get_a() { return _call_a; } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/public/output.js index e71667b3a948..7be984d4916e 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/public/output.js @@ -1,12 +1,10 @@ -var _computedKey, _initProto; +var _initProto; const dec = ()=>{}; -_computedKey = 'b'; -let _computedKey1 = _computedKey; class Foo { a() { return this.value; } - [_computedKey1]() { + ['b']() { return this.value; } constructor(){ @@ -25,3 +23,18 @@ class Foo { _computedKey ] ], [])); +var __ = { + writable: true, + value: [_initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 2, + "a" + ], + [ + dec, + 2, + 'b' + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/static-private/output.js index b3f3afe7936d..4ba61d4ce9c7 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/static-private/output.js @@ -22,6 +22,22 @@ var _a = { ], [])); _initStatic(Foo); })(); +var __ = { + writable: true, + value: (()=>{ + [_call_a, _initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 7, + "a", + function() { + return this.value; + } + ] + ], []).e; + _initStatic(Foo); + })() +}; _define_property(Foo, "value", 1); function get_a() { return _call_a; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/static-public/output.js index c841d334222f..10807b05f5e7 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/static-public/output.js @@ -1,12 +1,10 @@ -var _computedKey, _initStatic; +var _initStatic; const dec = ()=>{}; -_computedKey = 'b'; -let _computedKey1 = _computedKey; class Foo { static a() { return this.value; } - static [_computedKey1]() { + static ['b']() { return this.value; } } @@ -25,4 +23,22 @@ class Foo { ], [])); _initStatic(Foo); })(); +var __ = { + writable: true, + value: (()=>{ + [_initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 7, + "a" + ], + [ + dec, + 7, + 'b' + ] + ], []).e; + _initStatic(Foo); + })() +}; _define_property(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/private/output.js index e0ea231af691..3daf857df086 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/private/output.js @@ -2,7 +2,7 @@ var _call_a, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_a, _initProto] } = _apply_decs_2203_r(this, [ + [_call_a, _initProto] = _apply_decs_2203_r(this, [ [ dec, 2, @@ -11,7 +11,7 @@ class Foo { return this.value; } ] - ], [])); + ], []).e; } value = (_initProto(this), 1); get #a() { diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/public/output.js index 3de6c5a04a21..cd78b83b23fa 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/public/output.js @@ -1,9 +1,9 @@ -var _computedKey, _initProto; +var _initProto; const dec = ()=>{}; -_computedKey = 'b'; class Foo { static{ ({ e: [_initProto] } = _apply_decs_2203_r(this, [ + [_initProto] = _apply_decs_2203_r(this, [ [ dec, 2, @@ -12,15 +12,15 @@ class Foo { [ dec, 2, - _computedKey + 'b' ] - ], [])); + ], []).e; } value = (_initProto(this), 1); a() { return this.value; } - [_computedKey]() { + ['b']() { return this.value; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/static-private/output.js index b7bad0b82da4..3e29b42d410d 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/static-private/output.js @@ -2,7 +2,7 @@ var _call_a, _initStatic; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_a, _initStatic] } = _apply_decs_2203_r(this, [ + [_call_a, _initStatic] = _apply_decs_2203_r(this, [ [ dec, 7, @@ -11,7 +11,7 @@ class Foo { return this.value; } ] - ], [])); + ], []).e; _initStatic(this); } static value = 1; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/static-public/output.js index b9c87343bb5b..de597cc9e5aa 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/static-public/output.js @@ -1,9 +1,8 @@ -var _computedKey, _initStatic; +var _initStatic; const dec = ()=>{}; -_computedKey = 'b'; class Foo { static{ - ({ e: [_initStatic] } = _apply_decs_2203_r(this, [ + [_initStatic] = _apply_decs_2203_r(this, [ [ dec, 7, @@ -12,16 +11,16 @@ class Foo { [ dec, 7, - _computedKey + 'b' ] - ], [])); + ], []).e; _initStatic(this); } static value = 1; static a() { return this.value; } - static [_computedKey]() { + static ['b']() { return this.value; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc--to-es2015/initProto-existing-derived-constructor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc--to-es2015/initProto-existing-derived-constructor/output.js index ecc80e1cb79e..1fe948fb2275 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc--to-es2015/initProto-existing-derived-constructor/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc--to-es2015/initProto-existing-derived-constructor/output.js @@ -15,3 +15,13 @@ class A extends B { "method" ] ], [])); +var __ = { + writable: true, + value: [_initProto] = _apply_decs_2203_r(A, [ + [ + deco, + 2, + "method" + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc--to-es2015/valid-expression-formats/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc--to-es2015/valid-expression-formats/output.js index 6be25b3af1d7..c476a67dfdec 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc--to-es2015/valid-expression-formats/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc--to-es2015/valid-expression-formats/output.js @@ -20,6 +20,16 @@ class Foo { "bar" ] ], []), _Nested; + }, __ = { + writable: true, + value: [_init_bar] = _apply_decs_2203_r(_Nested, [ + [ + _dec, + 0, + "bar" + ] + ], []).e + }, _Nested; } constructor(){ _class_private_field_init(this, _a, { diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/all-decorators/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/all-decorators/output.js index db3dbf8a9f99..f0c7dd1a3b4d 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/all-decorators/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/all-decorators/output.js @@ -1,4 +1,4 @@ -var _initClass, _init_d, _call_f, _call_g, _call_g1, _init_h, _get___h, _set___h, _init_m, _call_o, _call_p, _call_q, _init_r, _get___r, _set___r, _init_a, _init_e, _init_i, _init_n, _initProto, _initStatic; +var _initClass, _init_d, _call_f, _call_g, _call_g1, _init_h, _get_h, _set_h, _init_m, _call_o, _call_p, _call_q, _init_r, _get_r, _set_r, _init_a, _init_e, _init_i, _init_n, _initProto, _initStatic; const dec = ()=>{}; let _Class; new class extends _identity { @@ -8,7 +8,7 @@ new class extends _identity { static{ class Class { static{ - ({ e: [_init_m, _call_o, _call_p, _call_q, _init_r, _get___r, _set___r, _init_i, _init_n, _init_d, _call_f, _call_g, _call_g1, _init_h, _get___h, _set___h, _init_a, _init_e, _initProto, _initStatic], c: [_Class, _initClass] } = _apply_decs_2203_r(this, [ + ({ e: [_init_m, _call_o, _call_p, _call_q, _init_r, _get_r, _set_r, _init_i, _init_n, _init_d, _call_f, _call_g, _call_g1, _init_h, _get_h, _set_h, _init_a, _init_e, _initProto, _initStatic], c: [_Class, _initClass] } = _apply_decs_2203_r(this, [ [ dec, 7, @@ -149,11 +149,12 @@ new class extends _identity { get c() {} set c(v) {} #___private_d_1 = _init_d(this); + #_private_d_1 = (_initProto(this), _init_d(this)); get d() { - return this.#___private_d_1; + return this.#_private_d_1; } set d(_v) { - this.#___private_d_1 = _v; + this.#_private_d_1 = _v; } #e = _init_e(this); get #f() { @@ -167,24 +168,24 @@ new class extends _identity { } #__h_2 = _init_h(this); get #h() { - return _get___h(this); + return _get_h(this); } set #h(_v) { - _set___h(this, _v); + _set_h(this, _v); } static i = _init_i(this); static j() {} static get k() {} static set l(v) {} static get m() { - return this.#___private_m_3; + return this.#_private_m_3; } static set m(_v) { - this.#___private_m_3 = _v; + this.#_private_m_3 = _v; } } } - #___private_m_3 = _init_m(this); + #_private_m_3 = _init_m(this); #n = _init_n(this); get #o() { return _call_o; @@ -197,9 +198,9 @@ new class extends _identity { } #__r_4 = _init_r(this); get #r() { - return _get___r(this); + return _get_r(this); } set #r(_v) { - _set___r(this, _v); + _set_r(this, _v); } }(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/initProto-existing-derived-constructor-multiple-super/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/initProto-existing-derived-constructor-multiple-super/output.js index 714d62417f3d..0240de3a90c0 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/initProto-existing-derived-constructor-multiple-super/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/initProto-existing-derived-constructor-multiple-super/output.js @@ -3,12 +3,13 @@ const dec = ()=>{}; class A extends B { static{ ({ e: [_initProto] } = _apply_decs_2203_r(this, [ + [_initProto] = _apply_decs_2203_r(this, [ [ deco, 2, "method" ] - ], [])); + ], []).e; } constructor(){ if (Math.random() > 0.5) { @@ -22,12 +23,13 @@ class A extends B { class C extends B { static{ ({ e: [_initProto1] } = _apply_decs_2203_r(this, [ + [_initProto1] = _apply_decs_2203_r(this, [ [ deco, 2, "method" ] - ], [])); + ], []).e; } constructor(){ try { diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/initProto-existing-derived-constructor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/initProto-existing-derived-constructor/output.js index 4f611d171f83..096bb75669ed 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/initProto-existing-derived-constructor/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/initProto-existing-derived-constructor/output.js @@ -3,12 +3,13 @@ const dec = ()=>{}; class A extends B { static{ ({ e: [_initProto] } = _apply_decs_2203_r(this, [ + [_initProto] = _apply_decs_2203_r(this, [ [ dec, 2, "method" ] - ], [])); + ], []).e; } constructor(){ let a = 2; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/private-keys-in-enclosing-class/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/private-keys-in-enclosing-class/output.js index 0c69c9c3bbf4..59954d876cf1 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/private-keys-in-enclosing-class/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/private-keys-in-enclosing-class/output.js @@ -2,12 +2,12 @@ const dec = ()=>{}; class A { #A = 1; static B = class B extends A { - #___private_a_1 = 2; + #_private_a_1 = 2; get a() { - return this.#___private_a_1; + return this.#_private_a_1; } set a(_v) { - this.#___private_a_1 = _v; + this.#_private_a_1 = _v; } getA() { return this.#A; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-array-pattern/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-array-pattern/output.js index 43ae0da394e7..61b9206128e5 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-array-pattern/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-array-pattern/output.js @@ -2,14 +2,14 @@ var _call_x, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_x, _initProto] } = _apply_decs_2203_r(this, [ + [_call_x, _initProto] = _apply_decs_2203_r(this, [ [ dec, 2, "x", function() {} ] - ], [])); + ], []).e; } constructor(){ _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-for-of/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-for-of/output.js index 21b09cf40aef..9f3dc8704a13 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-for-of/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-for-of/output.js @@ -2,14 +2,14 @@ var _call_x, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_x, _initProto] } = _apply_decs_2203_r(this, [ + [_call_x, _initProto] = _apply_decs_2203_r(this, [ [ dec, 2, "x", function() {} ] - ], [])); + ], []).e; } constructor(){ _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-object-pattern/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-object-pattern/output.js index 2edf0195def4..bf804c81d7d7 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-object-pattern/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-object-pattern/output.js @@ -2,14 +2,14 @@ var _call_x, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_x, _initProto] } = _apply_decs_2203_r(this, [ + [_call_x, _initProto] = _apply_decs_2203_r(this, [ [ dec, 2, "x", function() {} ] - ], [])); + ], []).e; } constructor(){ _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-rest/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-rest/output.js index de4b3ce7cc6d..036fa3153df5 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-rest/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-rest/output.js @@ -2,14 +2,14 @@ var _call_x, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_x, _initProto] } = _apply_decs_2203_r(this, [ + [_call_x, _initProto] = _apply_decs_2203_r(this, [ [ dec, 2, "x", function() {} ] - ], [])); + ], []).e; } constructor(){ _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-update/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-update/output.js index 7be60aa43908..54ad6a0d2f7d 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-update/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method-via-update/output.js @@ -2,14 +2,14 @@ var _call_x, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_x, _initProto] } = _apply_decs_2203_r(this, [ + [_call_x, _initProto] = _apply_decs_2203_r(this, [ [ dec, 2, "x", function() {} ] - ], [])); + ], []).e; } constructor(){ _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method/output.js index de22aad1c97d..5b57365c9757 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/setting-private-method/output.js @@ -2,14 +2,14 @@ var _call_x, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_x, _initProto] } = _apply_decs_2203_r(this, [ + [_call_x, _initProto] = _apply_decs_2203_r(this, [ [ dec, 2, "x", function() {} ] - ], [])); + ], []).e; } constructor(){ _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js index 1266b57cb05a..2e92a2fbcae5 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js @@ -3,9 +3,9 @@ const dec = ()=>{}; let _Foo; class Foo extends (_Bar = Bar) { static{ - ({ c: [_Foo, _initClass] } = _apply_decs_2203_r(this, [], [ + [_Foo, _initClass] = _apply_decs_2203_r(this, [], [ dec - ], _Bar)); + ]).c; } constructor(){ let foo = super(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-private-accessor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-private-accessor/output.js index 8a254e717976..9f5ea0f7f128 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-private-accessor/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-private-accessor/output.js @@ -3,6 +3,7 @@ const dec = ()=>{}; class Foo extends Bar { static{ ({ e: [_call_x, _initProto] } = _apply_decs_2203_r(this, [ + [_call_x, _initProto] = _apply_decs_2203_r(this, [ [ dec, 3, @@ -11,7 +12,7 @@ class Foo extends Bar { return super.foo(); } ] - ], [])); + ], []).e; } constructor(...args){ super(...args), _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-private-method/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-private-method/output.js index ecca37cb6eb2..56561d7af6ed 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-private-method/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-private-method/output.js @@ -2,7 +2,7 @@ var _call_x, _initProto; const dec = ()=>{}; class Foo extends Bar { static{ - ({ e: [_call_x, _initProto] } = _apply_decs_2203_r(this, [ + [_call_x, _initProto] = _apply_decs_2203_r(this, [ [ dec, 2, @@ -11,7 +11,7 @@ class Foo extends Bar { return super.foo(); } ] - ], [])); + ], []).e; } constructor(...args){ super(...args), _initProto(this); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/valid-expression-formats/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/valid-expression-formats/output.js index 203e60bff0d7..ebe3bf8cc9bf 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/valid-expression-formats/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/valid-expression-formats/output.js @@ -34,13 +34,13 @@ class Foo { _dec = this.#a; return class Nested { static{ - ({ e: [_init_bar] } = _apply_decs_2203_r(this, [ + [_init_bar] = _apply_decs_2203_r(this, [ [ _dec, 0, "bar" ] - ], [])); + ], []).e; } bar = _init_bar(this); }; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/accessor-simple/1/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/accessor-simple/1/output.js index ea145fb98cd3..0e685da0a7f2 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/accessor-simple/1/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/accessor-simple/1/output.js @@ -1,4 +1,4 @@ -var _initClass, _init_b, _init_c, _get___c, _set___c, _call_d, _initProto, _initStatic; +var _initClass, _init_b, _init_c, _get_c, _set_c, _call_d, _initProto, _initStatic; let _A; new class extends _identity { constructor(){ @@ -7,7 +7,7 @@ new class extends _identity { static{ class A { static{ - ({ e: [_init_b, _init_c, _get___c, _set___c, _call_d, _initProto, _initStatic], c: [_A, _initClass] } = _apply_decs_2203_r(this, [ + ({ e: [_init_b, _init_c, _get_c, _set_c, _call_d, _initProto, _initStatic], c: [_A, _initClass] } = _apply_decs_2203_r(this, [ [ dec3, 6, @@ -45,22 +45,22 @@ new class extends _identity { } a() {} static get b() { - return this.#___private_b_1; + return this.#_private_b_1; } static set b(_v) { - this.#___private_b_1 = _v; + this.#_private_b_1 = _v; } get #d() { return _call_d; } } } - #___private_b_1 = _init_b(this); + #_private_b_1 = _init_b(this); #__c_2 = _init_c(this); get #c() { - return _get___c(this); + return _get_c(this); } set #c(_v) { - _set___c(this, _v); + _set_c(this, _v); } }(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/accessor-static-method-initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/accessor-static-method-initializers/output.js index 82568d548199..576727af0688 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/accessor-static-method-initializers/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/accessor-static-method-initializers/output.js @@ -1,4 +1,4 @@ -var _dec, _dec1, _initClass, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _init_a, _call_c, _init_d, _get___d, _set___d, _initProto, _initStatic; +var _dec, _dec1, _initClass, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _init_a, _call_c, _init_d, _get_d, _set_d, _initProto, _initStatic; let _A; _dec = logClassDecoratorRun(0, 19, 29), _dec1 = logClassDecoratorRun(1, 18, 28), _dec2 = logAccessorDecoratorRun(2, 15, 31, 35), _dec3 = logAccessorDecoratorRun(3, 14, 30, 34), _dec4 = logMethodDecoratorRun(4, 11, 21, 25), _dec5 = logMethodDecoratorRun(5, 10, 20, 24), _dec6 = logMethodDecoratorRun(6, 13, 23, 27), _dec7 = logMethodDecoratorRun(7, 12, 22, 26), _dec8 = logAccessorDecoratorRun(8, 17, 33, 37), _dec9 = logAccessorDecoratorRun(9, 16, 32, 36); new class extends _identity { @@ -10,7 +10,7 @@ new class extends _identity { static{ class A { static{ - ({ e: [_call_c, _init_a, _init_d, _get___d, _set___d, _initProto, _initStatic], c: [_A, _initClass] } = _apply_decs_2203_r(this, [ + ({ e: [_call_c, _init_a, _init_d, _get_d, _set_d, _initProto, _initStatic], c: [_A, _initClass] } = _apply_decs_2203_r(this, [ [ [ _dec4, @@ -56,20 +56,20 @@ new class extends _identity { ])); _initStatic(this); } - #___private_a_1 = (_initProto(this), _init_a(this)); + #_private_a_1 = (_initProto(this), _init_a(this)); get a() { - return this.#___private_a_1; + return this.#_private_a_1; } set a(_v) { - this.#___private_a_1 = _v; + this.#_private_a_1 = _v; } static b() {} #__d_2 = _init_d(this); get #d() { - return _get___d(this); + return _get_d(this); } set #d(_v) { - _set___d(this, _v); + _set_d(this, _v); } constructor(){ this.a = this.#d = null; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/initializers/output.js index 239618fc796d..8ab7d9081eb6 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/initializers/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-ordering/initializers/output.js @@ -1,4 +1,4 @@ -var _dec, _dec1, _initClass, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec10, _dec11, _dec12, _dec13, _dec14, _dec15, _dec16, _dec17, _call_c, _call_d, _init_e, _init_f, _init_g, _get___g, _set___g, _init_h, _get___h, _set___h, _initProto, _initStatic; +var _dec, _dec1, _initClass, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec10, _dec11, _dec12, _dec13, _dec14, _dec15, _dec16, _dec17, _call_c, _call_d, _init_e, _init_f, _init_g, _get_g, _set_g, _init_h, _get_h, _set_h, _initProto, _initStatic; let _A; _dec = logDecoratorRun(0, 35, 45), _dec1 = logDecoratorRun(1, 34, 44), _dec2 = logDecoratorRun(2, 27, 47), _dec3 = logDecoratorRun(3, 26, 46), _dec4 = logDecoratorRun(4, 19, 37), _dec5 = logDecoratorRun(5, 18, 36), _dec6 = logDecoratorRun(6, 21, 39), _dec7 = logDecoratorRun(7, 20, 38), _dec8 = logDecoratorRun(8, 29, 49), _dec9 = logDecoratorRun(9, 28, 48), _dec10 = logDecoratorRun(10, 31, 51), _dec11 = logDecoratorRun(11, 30, 50), _dec12 = logDecoratorRun(12, 23, 41), _dec13 = logDecoratorRun(13, 22, 40), _dec14 = logDecoratorRun(14, 25, 43), _dec15 = logDecoratorRun(15, 24, 42), _dec16 = logDecoratorRun(16, 33, 53), _dec17 = logDecoratorRun(17, 32, 52); new class extends _identity { @@ -8,7 +8,7 @@ new class extends _identity { static{ class A { static{ - ({ e: [_call_c, _init_f, _init_g, _get___g, _set___g, _call_d, _init_e, _init_h, _get___h, _set___h, _initProto, _initStatic], c: [_A, _initClass] } = _apply_decs_2203_r(this, [ + ({ e: [_call_c, _init_f, _init_g, _get_g, _set_g, _call_d, _init_e, _init_h, _get_h, _set_h, _initProto, _initStatic], c: [_A, _initClass] } = _apply_decs_2203_r(this, [ [ [ _dec4, @@ -98,37 +98,37 @@ new class extends _identity { get #d() { return _call_d; } - #___private_e_1 = (_initProto(this), _init_e(this)); + #_private_e_1 = (_initProto(this), _init_e(this)); get e() { - return this.#___private_e_1; + return this.#_private_e_1; } set e(_v) { - this.#___private_e_1 = _v; + this.#_private_e_1 = _v; } static get f() { - return this.#___private_f_2; + return this.#_private_f_2; } static set f(_v) { - this.#___private_f_2 = _v; + this.#_private_f_2 = _v; } #__h_4 = _init_h(this); get #h() { - return _get___h(this); + return _get_h(this); } set #h(_v) { - _set___h(this, _v); + _set_h(this, _v); } } } get #c() { return _call_c; } - #___private_f_2 = _init_f(this); + #_private_f_2 = _init_f(this); #__g_3 = _init_g(this); get #g() { - return _get___g(this); + return _get_g(this); } set #g(_v) { - _set___g(this, _v); + _set_g(this, _v); } }(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/private/output.js index a8fa7f9adad4..b48895635520 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/private/output.js @@ -23,6 +23,19 @@ class Foo { } ] ], [])); +var __ = { + writable: true, + value: [_call_a, _initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 4, + "a", + function(v) { + return this.value = v; + } + ] + ], []).e +}; function set_a(v) { return _call_a(this, v); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/public/output.js index 3b6acbdb1f58..566d964b3eda 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/public/output.js @@ -1,12 +1,10 @@ -var _computedKey, _initProto; +var _initProto; const dec = ()=>{}; -_computedKey = 'b'; -let _computedKey1 = _computedKey; class Foo { set a(v) { return this.value = v; } - set [_computedKey1](v) { + set ['b'](v) { return this.value = v; } constructor(){ @@ -25,3 +23,18 @@ class Foo { _computedKey ] ], [])); +var __ = { + writable: true, + value: [_initProto] = _apply_decs_2203_r(Foo, [ + [ + dec, + 4, + "a" + ], + [ + dec, + 4, + 'b' + ] + ], []).e +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/static-private/output.js index 5bf26a4cc761..a5dc6faa4890 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/static-private/output.js @@ -22,6 +22,22 @@ var _a = { ], [])); _initStatic(Foo); })(); +var __ = { + writable: true, + value: (()=>{ + [_call_a, _initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 9, + "a", + function(v) { + return this.value = v; + } + ] + ], []).e; + _initStatic(Foo); + })() +}; _define_property(Foo, "value", 1); function set_a(v) { return _call_a(this, v); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/static-public/output.js index dd3200caf41c..e62a6cfc159f 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/static-public/output.js @@ -1,12 +1,10 @@ -var _computedKey, _initStatic; +var _initStatic; const dec = ()=>{}; -_computedKey = 'b'; -let _computedKey1 = _computedKey; class Foo { static set a(v) { return this.value = v; } - static set [_computedKey1](v) { + static set ['b'](v) { return this.value = v; } } @@ -25,4 +23,22 @@ class Foo { ], [])); _initStatic(Foo); })(); +var __ = { + writable: true, + value: (()=>{ + [_initStatic] = _apply_decs_2203_r(Foo, [ + [ + dec, + 9, + "a" + ], + [ + dec, + 9, + 'b' + ] + ], []).e; + _initStatic(Foo); + })() +}; _define_property(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/private/output.js index fb0608802bc7..9167f653fcef 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/private/output.js @@ -2,7 +2,7 @@ var _call_a, _initProto; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_a, _initProto] } = _apply_decs_2203_r(this, [ + [_call_a, _initProto] = _apply_decs_2203_r(this, [ [ dec, 4, @@ -11,7 +11,7 @@ class Foo { return this.value = v; } ] - ], [])); + ], []).e; } value = (_initProto(this), 1); set #a(v) { diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/public/output.js index c365616ec45b..9cf988e8bfe8 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/public/output.js @@ -1,9 +1,9 @@ -var _computedKey, _initProto; +var _initProto; const dec = ()=>{}; -_computedKey = 'b'; class Foo { static{ ({ e: [_initProto] } = _apply_decs_2203_r(this, [ + [_initProto] = _apply_decs_2203_r(this, [ [ dec, 4, @@ -12,15 +12,15 @@ class Foo { [ dec, 4, - _computedKey + 'b' ] - ], [])); + ], []).e; } value = (_initProto(this), 1); set a(v) { return this.value = v; } - set [_computedKey](v) { + set ['b'](v) { return this.value = v; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/static-private/output.js index b4ba0cf0b9ea..fef8ab816b78 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/static-private/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/static-private/output.js @@ -2,7 +2,7 @@ var _call_a, _initStatic; const dec = ()=>{}; class Foo { static{ - ({ e: [_call_a, _initStatic] } = _apply_decs_2203_r(this, [ + [_call_a, _initStatic] = _apply_decs_2203_r(this, [ [ dec, 9, @@ -11,7 +11,7 @@ class Foo { return this.value = v; } ] - ], [])); + ], []).e; _initStatic(this); } static value = 1; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/static-public/output.js index 174eb94b2fc1..6548da5f87ab 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/static-public/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/static-public/output.js @@ -1,9 +1,8 @@ -var _computedKey, _initStatic; +var _initStatic; const dec = ()=>{}; -_computedKey = 'b'; class Foo { static{ - ({ e: [_initStatic] } = _apply_decs_2203_r(this, [ + [_initStatic] = _apply_decs_2203_r(this, [ [ dec, 9, @@ -12,16 +11,16 @@ class Foo { [ dec, 9, - _computedKey + 'b' ] - ], [])); + ], []).e; _initStatic(this); } static value = 1; static set a(v) { return this.value = v; } - static set [_computedKey](v) { + static set ['b'](v) { return this.value = v; } } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/exec.js new file mode 100644 index 000000000000..c7716e947dda --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static accessor a; + @dec static accessor #a; + + @dec static accessor "b" + @dec static accessor ["c"]; + + @dec static accessor 0; + @dec static accessor [1]; + + @dec static accessor 2n; + @dec static accessor [3n]; + + @dec static accessor [f()]; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/input.js new file mode 100644 index 000000000000..c7716e947dda --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static accessor a; + @dec static accessor #a; + + @dec static accessor "b" + @dec static accessor ["c"]; + + @dec static accessor 0; + @dec static accessor [1]; + + @dec static accessor 2n; + @dec static accessor [3n]; + + @dec static accessor [f()]; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/options.json new file mode 100644 index 000000000000..e6953fa50f0b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "14.6.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/output.js new file mode 100644 index 000000000000..be77a55d45e6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/context-name/output.js @@ -0,0 +1,100 @@ +var _Foo; +let _init_a, _init_extra_a, _init_a2, _get_a, _set_a, _init_extra_a2, _init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2, _init_computedKey3, _init_extra_computedKey3, _init_computedKey4, _init_extra_computedKey4, _init_computedKey5, _init_extra_computedKey5, _init_computedKey6, _init_extra_computedKey6, _computedKey, _init_computedKey7, _init_extra_computedKey7; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +_computedKey = babelHelpers.toPropertyKey(f()); +class Foo { + static get a() { + return _A._; + } + static set a(v) { + _A._ = v; + } + static get "b"() { + return _C._; + } + static set "b"(v) { + _C._ = v; + } + static get ["c"]() { + return _D._; + } + static set ["c"](v) { + _D._ = v; + } + static get 0() { + return _E._; + } + static set 0(v) { + _E._ = v; + } + static get [1]() { + return _F._; + } + static set [1](v) { + _F._ = v; + } + static get 2n() { + return _G._; + } + static set 2n(v) { + _G._ = v; + } + static get [3n]() { + return _H._; + } + static set [3n](v) { + _H._ = v; + } + static get [_computedKey]() { + return _I._; + } + static set [_computedKey](v) { + _I._ = v; + } +} +_Foo = Foo; +function _set_a2(_this, v) { + _set_a(v); +} +function _get_a2(_this2) { + return _get_a(); +} +[_init_a, _init_extra_a, _init_a2, _get_a, _set_a, _init_extra_a2, _init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2, _init_computedKey3, _init_extra_computedKey3, _init_computedKey4, _init_extra_computedKey4, _init_computedKey5, _init_extra_computedKey5, _init_computedKey6, _init_extra_computedKey6, _init_computedKey7, _init_extra_computedKey7] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 9, "a"], [dec, 9, "a", o => babelHelpers.assertClassBrand(_Foo, o, _B)._, (o, v) => _B._ = babelHelpers.assertClassBrand(_Foo, o, v)], [dec, 9, "b"], [dec, 9, "c"], [dec, 9, 0], [dec, 9, 1], [dec, 9, 2n], [dec, 9, 3n], [dec, 9, _computedKey]]).e; +var _A = { + _: _init_a() +}; +var _B = { + _: (_init_extra_a(), _init_a2()) +}; +var _C = { + _: (_init_extra_a2(), _init_computedKey()) +}; +var _D = { + _: (_init_extra_computedKey(), _init_computedKey2()) +}; +var _E = { + _: (_init_extra_computedKey2(), _init_computedKey3()) +}; +var _F = { + _: (_init_extra_computedKey3(), _init_computedKey4()) +}; +var _G = { + _: (_init_extra_computedKey4(), _init_computedKey5()) +}; +var _H = { + _: (_init_extra_computedKey5(), _init_computedKey6()) +}; +var _I = { + _: (_init_extra_computedKey6(), _init_computedKey7()) +}; +_init_extra_computedKey7(); +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/private/exec.js new file mode 100644 index 000000000000..3759933f0304 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/private/exec.js @@ -0,0 +1,58 @@ +function dec({ get, set }, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(get.name).toEqual("get " + context.name); + expect(set.name).toEqual("set " + context.name); + return { + get() { + return get.call(this) + 1; + }, + + set(v) { + set.call(this, v + 1); + }, + + init(v) { + return v ? v : 1; + } + } +} + +class Foo { + @dec + accessor #a; + + @dec + accessor #b = 123; +} + +let foo = new Foo(); + +const aContext = foo['#aContext']; +const bContext = foo['#bContext']; + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(false); + +expect(aContext.access.get(foo)).toBe(2); +expect(() => aContext.access.get({})).toThrow(TypeError); +aContext.access.set(foo, 123); +expect(aContext.access.get(foo)).toBe(125); +expect(() => aContext.access.set({}, 456)).toThrow(TypeError); +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('accessor'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.access.get(foo)).toBe(124); +bContext.access.set(foo, 123); +expect(bContext.access.get(foo)).toBe(125); +expect(bContext.name).toBe('#b'); +expect(bContext.kind).toBe('accessor'); +expect(bContext.static).toBe(false); +expect(bContext.private).toBe(true); +expect(typeof bContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/private/input.js new file mode 100644 index 000000000000..aa152db91d94 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/private/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec + accessor #a; + + @dec + accessor #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/private/output.js new file mode 100644 index 000000000000..880c156be2e8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/private/output.js @@ -0,0 +1,16 @@ +var _Foo; +let _init_a, _get_a, _set_a, _init_extra_a, _init_b, _get_b, _set_b, _init_extra_b; +const dec = () => {}; +var _A = /*#__PURE__*/new WeakMap(); +var _Foo_brand = /*#__PURE__*/new WeakSet(); +var _B = /*#__PURE__*/new WeakMap(); +class Foo { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Foo_brand); + babelHelpers.classPrivateFieldInitSpec(this, _A, _init_a(this)); + babelHelpers.classPrivateFieldInitSpec(this, _B, (_init_extra_a(this), _init_b(this, 123))); + _init_extra_b(this); + } +} +_Foo = Foo; +[_init_a, _get_a, _set_a, _init_extra_a, _init_b, _get_b, _set_b, _init_extra_b] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 1, "a", o => babelHelpers.classPrivateFieldGet2(_A, o), (o, v) => babelHelpers.classPrivateFieldSet2(_A, o, v)], [dec, 1, "b", o => babelHelpers.classPrivateFieldGet2(_B, o), (o, v) => babelHelpers.classPrivateFieldSet2(_B, o, v)]], 0, _ => _Foo_brand.has(babelHelpers.checkInRHS(_))).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/public/exec.js new file mode 100644 index 000000000000..1e2196d2c0f7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/public/exec.js @@ -0,0 +1,82 @@ +function dec({ get, set }, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(get.name).toEqual("get " + context.name); + expect(set.name).toEqual("set " + context.name); + return { + get() { + return get.call(this) + 1; + }, + + set(v) { + set.call(this, v + 1); + }, + + init(v) { + return v ? v : 1; + } + } +} + +class Foo { + @dec + accessor a; + + @dec + accessor b = 123; + + @dec + accessor ['c'] = 456; +} + +let foo = new Foo(); + +const aContext = foo['aContext']; +const bContext = foo['bContext']; +const cContext = foo['cContext']; + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(foo.a).toBe(2); +expect(aContext.access.get(foo)).toBe(2); +foo.a = 123; +expect(foo.a).toBe(125); +expect(aContext.access.get(foo)).toBe(125); +aContext.access.set(foo, 456); +expect(foo.a).toBe(458); +expect(aContext.access.get(foo)).toBe(458); +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('accessor'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); +expect(foo.hasOwnProperty('a')).toBe(false); +expect(Foo.prototype.hasOwnProperty('a')).toBe(true); + +expect(foo.b).toBe(124); +foo.b = 123; +expect(foo.b).toBe(125); +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('accessor'); +expect(bContext.static).toBe(false); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); +expect(foo.hasOwnProperty('b')).toBe(false); +expect(Foo.prototype.hasOwnProperty('b')).toBe(true); + +expect(foo.c).toBe(457); +foo.c = 456; +expect(foo.c).toBe(458); +expect(cContext.name).toBe('c'); +expect(cContext.kind).toBe('accessor'); +expect(cContext.static).toBe(false); +expect(cContext.private).toBe(false); +expect(typeof cContext.addInitializer).toBe('function'); +expect(foo.hasOwnProperty('c')).toBe(false); +expect(Foo.prototype.hasOwnProperty('c')).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/public/input.js new file mode 100644 index 000000000000..bd8be5cbe225 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/public/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class Foo { + @dec + accessor a; + + @dec + accessor b = 123; + + @dec + accessor ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/public/output.js new file mode 100644 index 000000000000..3718157bda9c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/public/output.js @@ -0,0 +1,34 @@ +var _Foo; +let _init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey; +const dec = () => {}; +var _A = /*#__PURE__*/new WeakMap(); +var _B = /*#__PURE__*/new WeakMap(); +var _C = /*#__PURE__*/new WeakMap(); +class Foo { + constructor() { + babelHelpers.classPrivateFieldInitSpec(this, _A, _init_a(this)); + babelHelpers.classPrivateFieldInitSpec(this, _B, (_init_extra_a(this), _init_b(this, 123))); + babelHelpers.classPrivateFieldInitSpec(this, _C, (_init_extra_b(this), _init_computedKey(this, 456))); + _init_extra_computedKey(this); + } + get a() { + return babelHelpers.classPrivateFieldGet2(_A, this); + } + set a(v) { + babelHelpers.classPrivateFieldSet2(_A, this, v); + } + get b() { + return babelHelpers.classPrivateFieldGet2(_B, this); + } + set b(v) { + babelHelpers.classPrivateFieldSet2(_B, this, v); + } + get ['c']() { + return babelHelpers.classPrivateFieldGet2(_C, this); + } + set ['c'](v) { + babelHelpers.classPrivateFieldSet2(_C, this, v); + } +} +_Foo = Foo; +[_init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 1, "a"], [dec, 1, "b"], [dec, 1, 'c']]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-private/exec.js new file mode 100644 index 000000000000..395bb12d5b08 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-private/exec.js @@ -0,0 +1,57 @@ +function dec({ get, set }, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(get.name).toEqual("get " + context.name); + expect(set.name).toEqual("set " + context.name); + return { + get() { + return get.call(this) + 1; + }, + + set(v) { + set.call(this, v + 1); + }, + + init(v) { + return v ? v : 1; + } + } +} + +class Foo { + @dec + static accessor #a; + + @dec + static accessor #b = 123; +} + +const aContext = Foo['#aContext']; +const bContext = Foo['#bContext']; + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(false); + +expect(aContext.access.get(Foo)).toBe(2); +expect(() => aContext.access.get({})).toThrow(TypeError); +aContext.access.set(Foo, 123); +expect(aContext.access.get(Foo)).toBe(125); +expect(() => aContext.access.set({}, 456)).toThrow(TypeError); +expect(aContext.access.get(Foo)).toBe(125); +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('accessor'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.access.get(Foo)).toBe(124); +bContext.access.set(Foo, 123); +expect(bContext.access.get(Foo)).toBe(125); +expect(bContext.name).toBe('#b'); +expect(bContext.kind).toBe('accessor'); +expect(bContext.static).toBe(true); +expect(bContext.private).toBe(true); +expect(typeof bContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-private/input.js new file mode 100644 index 000000000000..c30e61d463bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-private/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec + static accessor #a; + + @dec + static accessor #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-private/output.js new file mode 100644 index 000000000000..17cdadc4f871 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-private/output.js @@ -0,0 +1,25 @@ +var _Foo; +let _init_a, _get_a, _set_a, _init_extra_a, _init_b, _get_b, _set_b, _init_extra_b; +const dec = () => {}; +class Foo {} +_Foo = Foo; +function _set_a2(_this, v) { + _set_a(v); +} +function _get_a2(_this2) { + return _get_a(); +} +function _set_b2(_this3, v) { + _set_b(v); +} +function _get_b2(_this4) { + return _get_b(); +} +[_init_a, _get_a, _set_a, _init_extra_a, _init_b, _get_b, _set_b, _init_extra_b] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 9, "a", o => babelHelpers.assertClassBrand(_Foo, o, _A)._, (o, v) => _A._ = babelHelpers.assertClassBrand(_Foo, o, v)], [dec, 9, "b", o => babelHelpers.assertClassBrand(_Foo, o, _B)._, (o, v) => _B._ = babelHelpers.assertClassBrand(_Foo, o, v)]]).e; +var _A = { + _: _init_a() +}; +var _B = { + _: (_init_extra_a(), _init_b(123)) +}; +_init_extra_b(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public-this/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public-this/exec.js new file mode 100644 index 000000000000..e981fac69393 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public-this/exec.js @@ -0,0 +1,12 @@ +// https://github.com/tc39/proposal-decorators/issues/468 + +class A { + static accessor x; + + @(() => {}) static accessor y; +} + +class B extends A {} + +expect(() => B.x).not.toThrow(); +expect(() => B.y).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public/exec.js new file mode 100644 index 000000000000..83632be8439b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public/exec.js @@ -0,0 +1,77 @@ +function dec({ get, set }, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(get.name).toEqual("get " + context.name); + expect(set.name).toEqual("set " + context.name); + return { + get() { + return get.call(this) + 1; + }, + + set(v) { + set.call(this, v + 1); + }, + + init(v) { + return v ? v : 1; + } + } +} + +class Foo { + @dec + static accessor a; + + @dec + static accessor b = 123; + + @dec + static accessor ['c'] = 456; +} + +const aContext = Foo['aContext']; +const bContext = Foo['bContext']; +const cContext = Foo['cContext']; + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(Foo.a).toBe(2); +expect(aContext.access.get(Foo)).toBe(2); +Foo.a = 123; +expect(Foo.a).toBe(125); +expect(aContext.access.get(Foo)).toBe(125); +aContext.access.set(Foo, 456); +expect(Foo.a).toBe(458); +expect(aContext.access.get(Foo)).toBe(458); +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('accessor'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); +expect(Foo.hasOwnProperty('a')).toBe(true); + +expect(Foo.b).toBe(124); +Foo.b = 123; +expect(Foo.b).toBe(125); +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('accessor'); +expect(bContext.static).toBe(true); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); +expect(Foo.hasOwnProperty('b')).toBe(true); + +expect(Foo.c).toBe(457); +Foo.c = 456; +expect(Foo.c).toBe(458); +expect(cContext.name).toBe('c'); +expect(cContext.kind).toBe('accessor'); +expect(cContext.static).toBe(true); +expect(cContext.private).toBe(false); +expect(typeof cContext.addInitializer).toBe('function'); +expect(Foo.hasOwnProperty('c')).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public/input.js new file mode 100644 index 000000000000..50f05c065848 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class Foo { + @dec + static accessor a; + + @dec + static accessor b = 123; + + @dec + static accessor ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public/output.js new file mode 100644 index 000000000000..3b2cbe29a2ef --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/static-public/output.js @@ -0,0 +1,35 @@ +var _Foo; +let _init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey; +const dec = () => {}; +class Foo { + static get a() { + return _A._; + } + static set a(v) { + _A._ = v; + } + static get b() { + return _B._; + } + static set b(v) { + _B._ = v; + } + static get ['c']() { + return _C._; + } + static set ['c'](v) { + _C._ = v; + } +} +_Foo = Foo; +[_init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 9, "a"], [dec, 9, "b"], [dec, 9, 'c']]).e; +var _A = { + _: _init_a() +}; +var _B = { + _: (_init_extra_a(), _init_b(123)) +}; +var _C = { + _: (_init_extra_b(), _init_computedKey(456)) +}; +_init_extra_computedKey(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-private/exec.js new file mode 100644 index 000000000000..51715be9f173 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-private/exec.js @@ -0,0 +1,31 @@ +class Foo { + accessor #a; + + accessor #b = 123; + + getA() { + return this.#a; + } + + setA(v) { + this.#a = v; + } + + getB() { + return this.#b; + } + + setB(v) { + this.#b = v; + } +} + +let foo = new Foo(); + +expect(foo.getA()).toBe(undefined); +foo.setA(123) +expect(foo.getA()).toBe(123); + +expect(foo.getB()).toBe(123); +foo.setB(456) +expect(foo.getB()).toBe(456); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-private/input.js new file mode 100644 index 000000000000..07804cb8a125 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-private/input.js @@ -0,0 +1,6 @@ +const dec = () => {}; +class Foo { + accessor #a; + + accessor #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-private/output.js new file mode 100644 index 000000000000..d5c894626bd6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-private/output.js @@ -0,0 +1,23 @@ +const dec = () => {}; +var _A = /*#__PURE__*/new WeakMap(); +var _Foo_brand = /*#__PURE__*/new WeakSet(); +var _B = /*#__PURE__*/new WeakMap(); +class Foo { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Foo_brand); + babelHelpers.classPrivateFieldInitSpec(this, _A, void 0); + babelHelpers.classPrivateFieldInitSpec(this, _B, 123); + } +} +function _get_a(_this) { + return babelHelpers.classPrivateFieldGet2(_A, _this); +} +function _set_a(_this2, v) { + babelHelpers.classPrivateFieldSet2(_A, _this2, v); +} +function _get_b(_this3) { + return babelHelpers.classPrivateFieldGet2(_B, _this3); +} +function _set_b(_this4, v) { + babelHelpers.classPrivateFieldSet2(_B, _this4, v); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-public/exec.js new file mode 100644 index 000000000000..5ccd5dcce44d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-public/exec.js @@ -0,0 +1,27 @@ +class Foo { + accessor a; + + accessor b = 123; + + accessor ['c'] = 456; +} + +let foo = new Foo(); + +expect(foo.a).toBe(undefined); +foo.a = 123; +expect(foo.a).toBe(123); +expect(foo.hasOwnProperty('a')).toBe(false); +expect(Foo.prototype.hasOwnProperty('a')).toBe(true); + +expect(foo.b).toBe(123); +foo.b = 456 +expect(foo.b).toBe(456); +expect(foo.hasOwnProperty('b')).toBe(false); +expect(Foo.prototype.hasOwnProperty('b')).toBe(true); + +expect(foo.c).toBe(456); +foo.c = 789 +expect(foo.c).toBe(789); +expect(foo.hasOwnProperty('c')).toBe(false); +expect(Foo.prototype.hasOwnProperty('c')).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-public/input.js new file mode 100644 index 000000000000..62dbd0c0381a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-public/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + accessor a; + + accessor b = 123; + + accessor ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-public/output.js new file mode 100644 index 000000000000..838c22f8927e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-public/output.js @@ -0,0 +1,29 @@ +const dec = () => {}; +var _A = /*#__PURE__*/new WeakMap(); +var _B = /*#__PURE__*/new WeakMap(); +var _C = /*#__PURE__*/new WeakMap(); +class Foo { + constructor() { + babelHelpers.classPrivateFieldInitSpec(this, _A, void 0); + babelHelpers.classPrivateFieldInitSpec(this, _B, 123); + babelHelpers.classPrivateFieldInitSpec(this, _C, 456); + } + get a() { + return babelHelpers.classPrivateFieldGet2(_A, this); + } + set a(v) { + babelHelpers.classPrivateFieldSet2(_A, this, v); + } + get b() { + return babelHelpers.classPrivateFieldGet2(_B, this); + } + set b(v) { + babelHelpers.classPrivateFieldSet2(_B, this, v); + } + get ['c']() { + return babelHelpers.classPrivateFieldGet2(_C, this); + } + set ['c'](v) { + babelHelpers.classPrivateFieldSet2(_C, this, v); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-private/exec.js new file mode 100644 index 000000000000..21defb3f24d8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-private/exec.js @@ -0,0 +1,29 @@ +class Foo { + static accessor #a; + + static accessor #b = 123; + + static getA() { + return this.#a; + } + + static setA(v) { + this.#a = v; + } + + static getB() { + return this.#b; + } + + static setB(v) { + this.#b = v; + } +} + +expect(Foo.getA()).toBe(undefined); +Foo.setA(123) +expect(Foo.getA()).toBe(123); + +expect(Foo.getB()).toBe(123); +Foo.setB(456) +expect(Foo.getB()).toBe(456); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-private/input.js new file mode 100644 index 000000000000..9e893b86b863 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-private/input.js @@ -0,0 +1,6 @@ +const dec = () => {}; +class Foo { + static accessor #a; + + static accessor #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-private/output.js new file mode 100644 index 000000000000..bd17c280c494 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-private/output.js @@ -0,0 +1,20 @@ +const dec = () => {}; +class Foo {} +function _get_a(_this) { + return _A._; +} +function _set_a(_this2, v) { + _A._ = v; +} +function _get_b(_this3) { + return _B._; +} +function _set_b(_this4, v) { + _B._ = v; +} +var _A = { + _: void 0 +}; +var _B = { + _: 123 +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-public/exec.js new file mode 100644 index 000000000000..d22a4e710dd8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-public/exec.js @@ -0,0 +1,22 @@ +class Foo { + static accessor a; + + static accessor b = 123; + + static accessor ['c'] = 456; +} + +expect(Foo.a).toBe(undefined); +Foo.a = 123; +expect(Foo.a).toBe(123); +expect(Foo.hasOwnProperty('a')).toBe(true); + +expect(Foo.b).toBe(123); +Foo.b = 456 +expect(Foo.b).toBe(456); +expect(Foo.hasOwnProperty('b')).toBe(true); + +expect(Foo.c).toBe(456); +Foo.c = 789 +expect(Foo.c).toBe(789); +expect(Foo.hasOwnProperty('c')).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-public/input.js new file mode 100644 index 000000000000..eb7463cb9fc1 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-public/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + static accessor a; + + static accessor b = 123; + + static accessor ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-public/output.js new file mode 100644 index 000000000000..c365830ea547 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors--to-es2015/undecorated-static-public/output.js @@ -0,0 +1,30 @@ +const dec = () => {}; +class Foo { + static get a() { + return _A._; + } + static set a(v) { + _A._ = v; + } + static get b() { + return _B._; + } + static set b(v) { + _B._ = v; + } + static get ['c']() { + return _C._; + } + static set ['c'](v) { + _C._ = v; + } +} +var _A = { + _: void 0 +}; +var _B = { + _: 123 +}; +var _C = { + _: 456 +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/exec.js new file mode 100644 index 000000000000..c7716e947dda --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static accessor a; + @dec static accessor #a; + + @dec static accessor "b" + @dec static accessor ["c"]; + + @dec static accessor 0; + @dec static accessor [1]; + + @dec static accessor 2n; + @dec static accessor [3n]; + + @dec static accessor [f()]; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/input.js new file mode 100644 index 000000000000..c7716e947dda --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static accessor a; + @dec static accessor #a; + + @dec static accessor "b" + @dec static accessor ["c"]; + + @dec static accessor 0; + @dec static accessor [1]; + + @dec static accessor 2n; + @dec static accessor [3n]; + + @dec static accessor [f()]; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/output.js new file mode 100644 index 000000000000..ea458778de8a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/context-name/output.js @@ -0,0 +1,83 @@ +let _init_a, _init_extra_a, _init_a2, _get_a, _set_a, _init_extra_a2, _init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2, _init_computedKey3, _init_extra_computedKey3, _init_computedKey4, _init_extra_computedKey4, _init_computedKey5, _init_extra_computedKey5, _init_computedKey6, _init_extra_computedKey6, _computedKey, _init_computedKey7, _init_extra_computedKey7; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +class Foo { + static { + [_init_a, _init_extra_a, _init_a2, _get_a, _set_a, _init_extra_a2, _init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2, _init_computedKey3, _init_extra_computedKey3, _init_computedKey4, _init_extra_computedKey4, _init_computedKey5, _init_extra_computedKey5, _init_computedKey6, _init_extra_computedKey6, _init_computedKey7, _init_extra_computedKey7] = babelHelpers.applyDecs2311(this, [], [[dec, 9, "a"], [dec, 9, "a", o => o.#B, (o, v) => o.#B = v], [dec, 9, "b"], [dec, 9, "c"], [dec, 9, 0], [dec, 9, 1], [dec, 9, 2n], [dec, 9, 3n], [dec, 9, _computedKey]]).e; + } + static #A = _init_a(); + static get a() { + return Foo.#A; + } + static set a(v) { + Foo.#A = v; + } + static #B = (_init_extra_a(), _init_a2()); + static set #a(v) { + _set_a(v); + } + static get #a() { + return _get_a(); + } + static #C = (_init_extra_a2(), _init_computedKey()); + static get "b"() { + return Foo.#C; + } + static set "b"(v) { + Foo.#C = v; + } + static #D = (_init_extra_computedKey(), _init_computedKey2()); + static get ["c"]() { + return Foo.#D; + } + static set ["c"](v) { + Foo.#D = v; + } + static #E = (_init_extra_computedKey2(), _init_computedKey3()); + static get 0() { + return Foo.#E; + } + static set 0(v) { + Foo.#E = v; + } + static #F = (_init_extra_computedKey3(), _init_computedKey4()); + static get [1]() { + return Foo.#F; + } + static set [1](v) { + Foo.#F = v; + } + static #G = (_init_extra_computedKey4(), _init_computedKey5()); + static get 2n() { + return Foo.#G; + } + static set 2n(v) { + Foo.#G = v; + } + static #H = (_init_extra_computedKey5(), _init_computedKey6()); + static get [3n]() { + return Foo.#H; + } + static set [3n](v) { + Foo.#H = v; + } + static #I = (_init_extra_computedKey6(), _init_computedKey7()); + static get [_computedKey = babelHelpers.toPropertyKey(f())]() { + return Foo.#I; + } + static set [_computedKey](v) { + Foo.#I = v; + } + static { + _init_extra_computedKey7(); + } +} +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/options.json new file mode 100644 index 000000000000..4c274676d3c2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/private/input.js new file mode 100644 index 000000000000..aa152db91d94 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/private/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec + accessor #a; + + @dec + accessor #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/private/output.js new file mode 100644 index 000000000000..5a58f90e2247 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/private/output.js @@ -0,0 +1,24 @@ +let _init_a, _get_a, _set_a, _init_extra_a, _init_b, _get_b, _set_b, _init_extra_b; +const dec = () => {}; +class Foo { + static { + [_init_a, _get_a, _set_a, _init_extra_a, _init_b, _get_b, _set_b, _init_extra_b] = babelHelpers.applyDecs2311(this, [], [[dec, 1, "a", o => o.#A, (o, v) => o.#A = v], [dec, 1, "b", o => o.#B, (o, v) => o.#B = v]], 0, _ => #a in _).e; + } + constructor() { + _init_extra_b(this); + } + #A = _init_a(this); + set #a(v) { + _set_a(this, v); + } + get #a() { + return _get_a(this); + } + #B = (_init_extra_a(this), _init_b(this, 123)); + set #b(v) { + _set_b(this, v); + } + get #b() { + return _get_b(this); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/public/input.js new file mode 100644 index 000000000000..bd8be5cbe225 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/public/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class Foo { + @dec + accessor a; + + @dec + accessor b = 123; + + @dec + accessor ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/public/output.js new file mode 100644 index 000000000000..07bc01645279 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/public/output.js @@ -0,0 +1,31 @@ +let _init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey; +const dec = () => {}; +class Foo { + static { + [_init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(this, [], [[dec, 1, "a"], [dec, 1, "b"], [dec, 1, 'c']]).e; + } + constructor() { + _init_extra_computedKey(this); + } + #A = _init_a(this); + get a() { + return this.#A; + } + set a(v) { + this.#A = v; + } + #B = (_init_extra_a(this), _init_b(this, 123)); + get b() { + return this.#B; + } + set b(v) { + this.#B = v; + } + #C = (_init_extra_b(this), _init_computedKey(this, 456)); + get ['c']() { + return this.#C; + } + set ['c'](v) { + this.#C = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-private/input.js new file mode 100644 index 000000000000..c30e61d463bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-private/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec + static accessor #a; + + @dec + static accessor #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-private/output.js new file mode 100644 index 000000000000..065b4d295856 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-private/output.js @@ -0,0 +1,24 @@ +let _init_a, _get_a, _set_a, _init_extra_a, _init_b, _get_b, _set_b, _init_extra_b; +const dec = () => {}; +class Foo { + static { + [_init_a, _get_a, _set_a, _init_extra_a, _init_b, _get_b, _set_b, _init_extra_b] = babelHelpers.applyDecs2311(this, [], [[dec, 9, "a", o => o.#A, (o, v) => o.#A = v], [dec, 9, "b", o => o.#B, (o, v) => o.#B = v]]).e; + } + static #A = _init_a(); + static set #a(v) { + _set_a(v); + } + static get #a() { + return _get_a(); + } + static #B = (_init_extra_a(), _init_b(123)); + static set #b(v) { + _set_b(v); + } + static get #b() { + return _get_b(); + } + static { + _init_extra_b(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public-inherited/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public-inherited/exec.js new file mode 100644 index 000000000000..e981fac69393 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public-inherited/exec.js @@ -0,0 +1,12 @@ +// https://github.com/tc39/proposal-decorators/issues/468 + +class A { + static accessor x; + + @(() => {}) static accessor y; +} + +class B extends A {} + +expect(() => B.x).not.toThrow(); +expect(() => B.y).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public-inherited/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public-inherited/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public-inherited/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public/input.js new file mode 100644 index 000000000000..50f05c065848 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class Foo { + @dec + static accessor a; + + @dec + static accessor b = 123; + + @dec + static accessor ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public/output.js new file mode 100644 index 000000000000..99c50150faf9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/static-public/output.js @@ -0,0 +1,31 @@ +let _init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey; +const dec = () => {}; +class Foo { + static { + [_init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(this, [], [[dec, 9, "a"], [dec, 9, "b"], [dec, 9, 'c']]).e; + } + static #A = _init_a(); + static get a() { + return Foo.#A; + } + static set a(v) { + Foo.#A = v; + } + static #B = (_init_extra_a(), _init_b(123)); + static get b() { + return Foo.#B; + } + static set b(v) { + Foo.#B = v; + } + static #C = (_init_extra_b(), _init_computedKey(456)); + static get ['c']() { + return Foo.#C; + } + static set ['c'](v) { + Foo.#C = v; + } + static { + _init_extra_computedKey(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-private/input.js new file mode 100644 index 000000000000..07804cb8a125 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-private/input.js @@ -0,0 +1,6 @@ +const dec = () => {}; +class Foo { + accessor #a; + + accessor #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-private/output.js new file mode 100644 index 000000000000..50efd9ecf14f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-private/output.js @@ -0,0 +1,17 @@ +const dec = () => {}; +class Foo { + #A; + get #a() { + return this.#A; + } + set #a(v) { + this.#A = v; + } + #B = 123; + get #b() { + return this.#B; + } + set #b(v) { + this.#B = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-public/input.js new file mode 100644 index 000000000000..62dbd0c0381a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-public/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + accessor a; + + accessor b = 123; + + accessor ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-public/output.js new file mode 100644 index 000000000000..0082fd52b442 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-public/output.js @@ -0,0 +1,24 @@ +const dec = () => {}; +class Foo { + #A; + get a() { + return this.#A; + } + set a(v) { + this.#A = v; + } + #B = 123; + get b() { + return this.#B; + } + set b(v) { + this.#B = v; + } + #C = 456; + get ['c']() { + return this.#C; + } + set ['c'](v) { + this.#C = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-private/input.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-private/input.mjs new file mode 100644 index 000000000000..c16cffed096d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-private/input.mjs @@ -0,0 +1,18 @@ +const dec = () => {}; +class Foo { + static accessor #a; + + static accessor #b = 123; +} + +Foo = class { + static accessor #a; + + static accessor #b = 123; +} + +export default class { + static accessor #a; + + static accessor #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-private/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-private/output.mjs new file mode 100644 index 000000000000..c5d96b837e02 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-private/output.mjs @@ -0,0 +1,49 @@ +const dec = () => {}; +class Foo { + static #A; + static get #a() { + return Foo.#A; + } + static set #a(v) { + Foo.#A = v; + } + static #B = 123; + static get #b() { + return Foo.#B; + } + static set #b(v) { + Foo.#B = v; + } +} +Foo = class Foo { + static #A; + static get #a() { + return Foo.#A; + } + static set #a(v) { + Foo.#A = v; + } + static #B = 123; + static get #b() { + return Foo.#B; + } + static set #b(v) { + Foo.#B = v; + } +}; +export default class _Class { + static #A; + static get #a() { + return _Class.#A; + } + static set #a(v) { + _Class.#A = v; + } + static #B = 123; + static get #b() { + return _Class.#B; + } + static set #b(v) { + _Class.#B = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-public/input.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-public/input.mjs new file mode 100644 index 000000000000..cc118e69f931 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-public/input.mjs @@ -0,0 +1,24 @@ +const dec = () => {}; +class Foo { + static accessor a; + + static accessor b = 123; + + static accessor ['c'] = 456; +} + +Foo = class { + static accessor a; + + static accessor b = 123; + + static accessor ['c'] = 456; +} + +export default class { + static accessor a; + + static accessor b = 123; + + static accessor ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-public/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-public/output.mjs new file mode 100644 index 000000000000..0c4b69fb8da8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-accessors/undecorated-static-public/output.mjs @@ -0,0 +1,70 @@ +const dec = () => {}; +class Foo { + static #A; + static get a() { + return Foo.#A; + } + static set a(v) { + Foo.#A = v; + } + static #B = 123; + static get b() { + return Foo.#B; + } + static set b(v) { + Foo.#B = v; + } + static #C = 456; + static get ['c']() { + return Foo.#C; + } + static set ['c'](v) { + Foo.#C = v; + } +} +Foo = class Foo { + static #A; + static get a() { + return Foo.#A; + } + static set a(v) { + Foo.#A = v; + } + static #B = 123; + static get b() { + return Foo.#B; + } + static set b(v) { + Foo.#B = v; + } + static #C = 456; + static get ['c']() { + return Foo.#C; + } + static set ['c'](v) { + Foo.#C = v; + } +}; +export default class _Class { + static #A; + static get a() { + return _Class.#A; + } + static set a(v) { + _Class.#A = v; + } + static #B = 123; + static get b() { + return _Class.#B; + } + static set b(v) { + _Class.#B = v; + } + static #C = 456; + static get ['c']() { + return _Class.#C; + } + static set ['c'](v) { + _Class.#C = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/ctx/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/ctx/exec.js new file mode 100644 index 000000000000..ec0949c1390b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/ctx/exec.js @@ -0,0 +1,9 @@ +const logs = []; +function dec(value, ctx) { + logs.push(ctx.kind, ctx.name); +} + +@dec +class A {} + +expect(logs).toEqual(["class", "A"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-classes/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-classes/exec.js new file mode 100644 index 000000000000..2bfa992f5a3a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-classes/exec.js @@ -0,0 +1,23 @@ +function decorateA(target) { + return class extends target { + a() { + return "a"; + } + }; +} + +function decorateB(target) { + return class extends target { + b() { + return "b"; + } + }; +} + +@decorateB +@decorateA +class Target {} + +const target = new Target(); +expect(target.a()).toBe("a"); +expect(target.b()).toBe("b"); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-fields/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-fields/exec.js new file mode 100644 index 000000000000..9d5c4bbf3d15 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-fields/exec.js @@ -0,0 +1,14 @@ +var value; +const classDec = (Class) => { + value = (new Class).m; + return Class +}; + +const memberDec = () => () => 42; + +@classDec +class C { + @memberDec m; +} + +expect(value).toBe(42); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-fields/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-fields/input.js new file mode 100644 index 000000000000..8689cf13f9e5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-fields/input.js @@ -0,0 +1,12 @@ +var value; +const classDec = (Class) => { + value = (new Class).p; + return Class +}; + +const memberDec = () => () => 42; + +@classDec +class C { + @memberDec m; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-fields/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-fields/output.js new file mode 100644 index 000000000000..b99261348444 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-fields/output.js @@ -0,0 +1,21 @@ +var _C2; +let _initClass, _init_m, _init_extra_m; +var value; +const classDec = Class => { + value = new Class().p; + return Class; +}; +const memberDec = () => () => 42; +let _C; +class C { + constructor() { + babelHelpers.defineProperty(this, "m", _init_m(this)); + _init_extra_m(this); + } +} +_C2 = C; +({ + e: [_init_m, _init_extra_m], + c: [_C, _initClass] +} = babelHelpers.applyDecs2311(_C2, [classDec], [[memberDec, 0, "m"]])); +_initClass(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-methods/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-methods/exec.js new file mode 100644 index 000000000000..a85569beafbc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-methods/exec.js @@ -0,0 +1,14 @@ +var value; +const classDec = (Class) => { + value = (new Class).m(); + return Class +}; + +const memberDec = () => () => 42; + +@classDec +class C { + @memberDec m() {}; +} + +expect(value).toBe(42); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-methods/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-methods/input.js new file mode 100644 index 000000000000..7d8094583001 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-methods/input.js @@ -0,0 +1,12 @@ +var value; +const classDec = (Class) => { + value = (new Class).m(); + return Class +}; + +const memberDec = () => () => 42; + +@classDec +class C { + @memberDec m() {}; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-methods/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-methods/output.js new file mode 100644 index 000000000000..189759b9a030 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/decorator-access-modified-methods/output.js @@ -0,0 +1,21 @@ +var _C2; +let _initProto, _initClass; +var value; +const classDec = Class => { + value = new Class().m(); + return Class; +}; +const memberDec = () => () => 42; +let _C; +class C { + constructor() { + _initProto(this); + } + m() {} +} +_C2 = C; +({ + e: [_initProto], + c: [_C, _initClass] +} = babelHelpers.applyDecs2311(_C2, [classDec], [[memberDec, 2, "m"]])); +_initClass(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions-static-blocks/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions-static-blocks/input.js new file mode 100644 index 000000000000..853ac0e6a43b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions-static-blocks/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +const A = @dec class A { static {} } +const B = @dec class C { static {} } +const D = @dec class { static {} } +const E = (@dec class { static {} }, 123); +const F = [@dec class G { static {} }, @dec class { static {} }]; +const H = @dec class extends I { static {} }; +const J = @dec class K extends L { static {} }; + +function classFactory() { + return @dec class { static {} } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions-static-blocks/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions-static-blocks/output.js new file mode 100644 index 000000000000..d7076155f7b0 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions-static-blocks/output.js @@ -0,0 +1,51 @@ +var _Class, _A3, _Class2, _C3, _Class3, _D3, _Class4, _Class5, _Class6, _G3, _Class7, _Class8, _I, _Class9, _H3, _L, _Class10, _K3; +let _initClass, _A, _A2, _initClass2, _C, _C2, _initClass3, _D, _D2, _initClass4, _decorated_class, _ref, _initClass5, _G, _G2, _initClass6, _decorated_class2, _ref2, _initClass7, _H, _H2, _initClass8, _K, _K2; +const dec = () => {}; +const A = (new (_A2 = (_A3 = class A {}, [_A, _initClass] = babelHelpers.applyDecs2311(_A3, [dec], []).c, _A3), _Class = class extends babelHelpers.identity { + constructor() { + super(_A), (() => {})(), _initClass(); + } +}, babelHelpers.defineProperty(_Class, _A2, void 0), _Class)(), _A); +const B = (new (_C2 = (_C3 = class C {}, [_C, _initClass2] = babelHelpers.applyDecs2311(_C3, [dec], []).c, _C3), _Class2 = class extends babelHelpers.identity { + constructor() { + super(_C), (() => {})(), _initClass2(); + } +}, babelHelpers.defineProperty(_Class2, _C2, void 0), _Class2)(), _C); +const D = (new (_D2 = (_D3 = class D {}, [_D, _initClass3] = babelHelpers.applyDecs2311(_D3, [dec], []).c, _D3), _Class3 = class extends babelHelpers.identity { + constructor() { + super(_D), (() => {})(), _initClass3(); + } +}, babelHelpers.defineProperty(_Class3, _D2, void 0), _Class3)(), _D); +const E = (new (_ref = (_Class5 = class _ref {}, [_decorated_class, _initClass4] = babelHelpers.applyDecs2311(_Class5, [dec], []).c, _Class5), _Class4 = class extends babelHelpers.identity { + constructor() { + super(_decorated_class), (() => {})(), _initClass4(); + } +}, babelHelpers.defineProperty(_Class4, _ref, void 0), _Class4)(), _decorated_class, 123); +const F = [(new (_G2 = (_G3 = class G {}, [_G, _initClass5] = babelHelpers.applyDecs2311(_G3, [dec], []).c, _G3), _Class6 = class extends babelHelpers.identity { + constructor() { + super(_G), (() => {})(), _initClass5(); + } +}, babelHelpers.defineProperty(_Class6, _G2, void 0), _Class6)(), _G), (new (_ref2 = (_Class8 = class _ref2 {}, [_decorated_class2, _initClass6] = babelHelpers.applyDecs2311(_Class8, [dec], []).c, _Class8), _Class7 = class extends babelHelpers.identity { + constructor() { + super(_decorated_class2), (() => {})(), _initClass6(); + } +}, babelHelpers.defineProperty(_Class7, _ref2, void 0), _Class7)(), _decorated_class2)]; +const H = (new (_H2 = (_H3 = class H extends (_I = I) {}, [_H, _initClass7] = babelHelpers.applyDecs2311(_H3, [dec], [], 0, void 0, _I).c, _H3), _Class9 = class extends babelHelpers.identity { + constructor() { + super(_H), (() => {})(), _initClass7(); + } +}, babelHelpers.defineProperty(_Class9, _H2, void 0), _Class9)(), _H); +const J = (new (_K2 = (_K3 = class K extends (_L = L) {}, [_K, _initClass8] = babelHelpers.applyDecs2311(_K3, [dec], [], 0, void 0, _L).c, _K3), _Class10 = class extends babelHelpers.identity { + constructor() { + super(_K), (() => {})(), _initClass8(); + } +}, babelHelpers.defineProperty(_Class10, _K2, void 0), _Class10)(), _K); +function classFactory() { + var _Class11, _Class12; + let _initClass9, _decorated_class3, _ref3; + return new (_ref3 = (_Class12 = class _ref3 {}, [_decorated_class3, _initClass9] = babelHelpers.applyDecs2311(_Class12, [dec], []).c, _Class12), _Class11 = class extends babelHelpers.identity { + constructor() { + super(_decorated_class3), (() => {})(), _initClass9(); + } + }, babelHelpers.defineProperty(_Class11, _ref3, void 0), _Class11)(), _decorated_class3; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions/input.js new file mode 100644 index 000000000000..77060bea50ff --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +const A = @dec class A {} +const B = @dec class C {} +const D = @dec class {} +const E = (@dec class {}, 123); +const F = [@dec class G {}, @dec class {}]; +const H = @dec class extends I {}; +const J = @dec class K extends L {}; + +function classFactory() { + return @dec class {} +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions/output.js new file mode 100644 index 000000000000..d1bf66d8a996 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/expressions/output.js @@ -0,0 +1,15 @@ +var _A2, _C2, _D2, _Class, _G2, _Class2, _I, _H2, _L, _K2; +let _initClass, _A, _initClass2, _C, _initClass3, _D, _initClass4, _decorated_class, _initClass5, _G, _initClass6, _decorated_class2, _initClass7, _H, _initClass8, _K; +const dec = () => {}; +const A = (_A2 = class A {}, [_A, _initClass] = babelHelpers.applyDecs2311(_A2, [dec], []).c, _initClass(), _A); +const B = (_C2 = class C {}, [_C, _initClass2] = babelHelpers.applyDecs2311(_C2, [dec], []).c, _initClass2(), _C); +const D = (_D2 = class D {}, [_D, _initClass3] = babelHelpers.applyDecs2311(_D2, [dec], []).c, _initClass3(), _D); +const E = (_Class = class {}, [_decorated_class, _initClass4] = babelHelpers.applyDecs2311(_Class, [dec], []).c, _initClass4(), _decorated_class, 123); +const F = [(_G2 = class G {}, [_G, _initClass5] = babelHelpers.applyDecs2311(_G2, [dec], []).c, _initClass5(), _G), (_Class2 = class {}, [_decorated_class2, _initClass6] = babelHelpers.applyDecs2311(_Class2, [dec], []).c, _initClass6(), _decorated_class2)]; +const H = (_H2 = class H extends (_I = I) {}, [_H, _initClass7] = babelHelpers.applyDecs2311(_H2, [dec], [], 0, void 0, _I).c, _initClass7(), _H); +const J = (_K2 = class K extends (_L = L) {}, [_K, _initClass8] = babelHelpers.applyDecs2311(_K2, [dec], [], 0, void 0, _L).c, _initClass8(), _K); +function classFactory() { + var _Class3; + let _initClass9, _decorated_class3; + return _Class3 = class {}, [_decorated_class3, _initClass9] = babelHelpers.applyDecs2311(_Class3, [dec], []).c, _initClass9(), _decorated_class3; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/inheritance/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/inheritance/exec.js new file mode 100644 index 000000000000..889e8c102cf4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/inheritance/exec.js @@ -0,0 +1,18 @@ +let count = 0; + +function dec1(Klass) { + expect(++count).toBe(1); + expect(Klass.name).toBe('Bar'); +} + +@dec1 +class Bar {} + +function dec2(Klass) { + expect(++count).toBe(2); + expect(Klass.name).toBe('Foo'); + expect(Object.getPrototypeOf(Klass)).toBe(Bar); +} + +@dec2 +class Foo extends Bar {} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/inheritance/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/inheritance/input.js new file mode 100644 index 000000000000..96a13523506c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/inheritance/input.js @@ -0,0 +1,7 @@ +const dec1 = () => {}; +const dec2 = () => {}; +@dec1 +class Bar {} + +@dec2 +class Foo extends Bar {} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/inheritance/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/inheritance/output.js new file mode 100644 index 000000000000..a66e08056769 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/inheritance/output.js @@ -0,0 +1,14 @@ +var _Bar2, _Bar3, _Foo2; +let _initClass, _initClass2; +const dec1 = () => {}; +const dec2 = () => {}; +let _Bar; +class Bar {} +_Bar2 = Bar; +[_Bar, _initClass] = babelHelpers.applyDecs2311(_Bar2, [dec1], []).c; +_initClass(); +let _Foo; +class Foo extends (_Bar3 = _Bar) {} +_Foo2 = Foo; +[_Foo, _initClass2] = babelHelpers.applyDecs2311(_Foo2, [dec2], [], 0, void 0, _Bar3).c; +_initClass2(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/initializers/exec.js new file mode 100644 index 000000000000..aefc3ba5b88c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/initializers/exec.js @@ -0,0 +1,41 @@ +function dec1(Foo, { addInitializer }) { + expect(Foo.field).toBe(undefined); + addInitializer(() => { + Foo.initField = 123; + }); +} + +@dec1 +class Foo { + static { + expect(this.initField).toBe(undefined); + } + + static field = 123; +} + +expect(Foo.initField).toBe(123); +expect(Foo.field).toBe(123); + +function dec2(Bar, { addInitializer }) { + expect(Bar.field).toBe(123); + expect(Bar.otherField).toBe(undefined); + expect(Bar.initField).toBe(123); + addInitializer(() => { + Bar.initField = 456; + }); +} + +@dec2 +class Bar extends Foo { + static { + expect(this.initField).toBe(123); + this.otherField = 456; + } + + static field = 456; +} + +expect(Bar.initField).toBe(456); +expect(Bar.field).toBe(456); +expect(Bar.otherField).toBe(456); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/initializers/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/initializers/input.js new file mode 100644 index 000000000000..87c785d39a93 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/initializers/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +@dec +class Foo { + static field = 123; +} + +@dec +class Bar extends Foo { + static { + this.otherField = 456; + } + + static field = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/initializers/output.js new file mode 100644 index 000000000000..613307eac010 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/initializers/output.js @@ -0,0 +1,17 @@ +var _Class, _Foo3, _Foo4, _Class2, _Bar3; +let _initClass, _Foo2, _initClass2, _Bar2; +const dec = () => {}; +let _Foo; +new (_Foo2 = (_Foo3 = class Foo {}, [_Foo, _initClass] = babelHelpers.applyDecs2311(_Foo3, [dec], []).c, _Foo3), _Class = class extends babelHelpers.identity { + constructor() { + super(_Foo), babelHelpers.defineProperty(this, "field", 123), _initClass(); + } +}, babelHelpers.defineProperty(_Class, _Foo2, void 0), _Class)(); +let _Bar; +new (_Bar2 = (_Bar3 = class Bar extends (_Foo4 = _Foo) {}, [_Bar, _initClass2] = babelHelpers.applyDecs2311(_Bar3, [dec], [], 0, void 0, _Foo4).c, _Bar3), _Class2 = class extends babelHelpers.identity { + constructor() { + super(_Bar), babelHelpers.defineProperty(this, "field", ((() => { + this.otherField = 456; + })(), 123)), _initClass2(); + } +}, babelHelpers.defineProperty(_Class2, _Bar2, void 0), _Class2)(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-decorator-initializer-this/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-decorator-initializer-this/exec.js new file mode 100644 index 000000000000..c9be25950ca3 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-decorator-initializer-this/exec.js @@ -0,0 +1,44 @@ + +let original, replaced, accessorThis, getterThis, setterThis, methodThis, propertyThis, classThis; + +function dec(Klass, context) { + original = Klass; + replaced = class extends Klass {}; + + context.addInitializer(function () { + classThis = this; + }) + + return replaced; +} + +function captureInitializerThis(callback) { + return function (_, context) { + context.addInitializer(function () { + callback(this); + }) + } +} + +@dec +class Foo { + @(captureInitializerThis(v => accessorThis = v)) + static accessor accessor; + @(captureInitializerThis(v => getterThis = v)) + static get getter() {}; + @(captureInitializerThis(v => setterThis = v)) + static set setter(_) {}; + @(captureInitializerThis(v => methodThis = v)) + static method() {} + @(captureInitializerThis(v => propertyThis = v)) + static property; +} + +expect(getterThis).toBe(original); +expect(setterThis).toBe(original); +expect(methodThis).toBe(original); + +expect(accessorThis).toBe(replaced); +expect(propertyThis).toBe(replaced); + +expect(classThis).toBe(replaced); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-decorator-initializer-this/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-decorator-initializer-this/input.js new file mode 100644 index 000000000000..d6335133be0e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-decorator-initializer-this/input.js @@ -0,0 +1,35 @@ + +let original, replaced, accessorThis, getterThis, setterThis, methodThis, propertyThis, classThis; + +function dec(Klass, context) { + original = Klass; + replaced = class extends Klass {}; + + context.addInitializer(function () { + classThis = this; + }) + + return replaced; +} + +function captureInitializerThis(callback) { + return function (_, context) { + context.addInitializer(function () { + callback(this); + }) + } +} + +@dec +class Foo { + @(captureInitializerThis(v => accessorThis = v)) + static accessor accessor; + @(captureInitializerThis(v => getterThis = v)) + static get getter() {}; + @(captureInitializerThis(v => setterThis = v)) + static set setter(_) {}; + @(captureInitializerThis(v => methodThis = v)) + static method() {} + @(captureInitializerThis(v => propertyThis = v)) + static property; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-decorator-initializer-this/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-decorator-initializer-this/output.js new file mode 100644 index 000000000000..81057fe244ee --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-decorator-initializer-this/output.js @@ -0,0 +1,42 @@ +var _Class, _A, _Foo3; +let _initStatic, _initClass, _init_accessor, _init_extra_accessor, _init_property, _init_extra_property, _Foo2; +let original, replaced, accessorThis, getterThis, setterThis, methodThis, propertyThis, classThis; +function dec(Klass, context) { + original = Klass; + replaced = class extends Klass {}; + context.addInitializer(function () { + classThis = this; + }); + return replaced; +} +function captureInitializerThis(callback) { + return function (_, context) { + context.addInitializer(function () { + callback(this); + }); + }; +} +let _Foo; +new (_A = /*#__PURE__*/new WeakMap(), _Foo2 = (_Foo3 = class Foo { + static get accessor() { + return babelHelpers.classPrivateFieldGet2(_A, Foo); + } + static set accessor(v) { + babelHelpers.classPrivateFieldSet2(_A, Foo, v); + } + static get getter() {} + static set setter(_) {} + static method() {} +}, (() => { + ({ + e: [_init_accessor, _init_extra_accessor, _init_property, _init_extra_property, _initStatic], + c: [_Foo, _initClass] + } = babelHelpers.applyDecs2311(_Foo3, [dec], [[captureInitializerThis(v => accessorThis = v), 9, "accessor"], [captureInitializerThis(v => getterThis = v), 11, "getter"], [captureInitializerThis(v => setterThis = v), 12, "setter"], [captureInitializerThis(v => methodThis = v), 10, "method"], [captureInitializerThis(v => propertyThis = v), 8, "property"]])); + _initStatic(_Foo3); +})(), _Foo3), _Class = class extends babelHelpers.identity { + constructor() { + super(_Foo), babelHelpers.classPrivateFieldInitSpec(this, _A, _init_accessor()), babelHelpers.defineProperty(this, "property", (_init_extra_accessor(), _init_property())), (() => { + _init_extra_property(); + })(), _initClass(); + } +}, babelHelpers.defineProperty(_Class, _Foo2, void 0), _Class)(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-installed-on-correct-class/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-installed-on-correct-class/exec.js new file mode 100644 index 000000000000..3a7d4a53c32f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-installed-on-correct-class/exec.js @@ -0,0 +1,41 @@ +let hasX, hasA, hasM, OriginalFoo; + +class Bar {} + +function dec(Foo) { + OriginalFoo = Foo; + return Bar; +} + +@dec +class Foo { + static #x; + static accessor #a; + static #m() {} + + static x; + static accessor a; + static m() {} + + static { + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + } +} + +expect(hasX(Bar)).toBe(true); +expect(hasA(Bar)).toBe(true); +expect(hasM(Bar)).toBe(true); +expect(hasX(OriginalFoo)).toBe(false); +expect(hasA(OriginalFoo)).toBe(false); +expect(hasM(OriginalFoo)).toBe(false); + +expect(Bar.hasOwnProperty("x")).toBe(true); +expect(OriginalFoo.hasOwnProperty("x")).toBe(false); + +expect(Bar.hasOwnProperty("a")).toBe(false); +expect(OriginalFoo.hasOwnProperty("a")).toBe(true); + +expect(Bar.hasOwnProperty("m")).toBe(false); +expect(OriginalFoo.hasOwnProperty("m")).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-installed-on-correct-class/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-installed-on-correct-class/input.js new file mode 100644 index 000000000000..c62f272ff354 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-installed-on-correct-class/input.js @@ -0,0 +1,19 @@ +const dec = () => {}; +let hasX, hasA, hasM; + +@dec +class Foo { + static #x; + static accessor #a; + static #m() {} + + static x; + static accessor a; + static m() {} + + static { + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-installed-on-correct-class/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-installed-on-correct-class/output.js new file mode 100644 index 000000000000..498f9d298a51 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-installed-on-correct-class/output.js @@ -0,0 +1,29 @@ +var _Class, _x, _A, _Class_brand, _B, _Foo3; +let _initClass, _Foo2; +const dec = () => {}; +let hasX, hasA, hasM; +let _Foo; +new (_x = /*#__PURE__*/new WeakMap(), _A = /*#__PURE__*/new WeakMap(), _Class_brand = /*#__PURE__*/new WeakSet(), _B = /*#__PURE__*/new WeakMap(), _Foo2 = (_Foo3 = class Foo { + static get a() { + return babelHelpers.classPrivateFieldGet2(_B, _Foo); + } + static set a(v) { + babelHelpers.classPrivateFieldSet2(_B, _Foo, v); + } + static m() {} +}, [_Foo, _initClass] = babelHelpers.applyDecs2311(_Foo3, [dec], []).c, _Foo3), _Class = class extends babelHelpers.identity { + constructor() { + super(_Foo), babelHelpers.classPrivateMethodInitSpec(this, _Class_brand), babelHelpers.classPrivateFieldInitSpec(this, _x, void 0), babelHelpers.classPrivateFieldInitSpec(this, _A, void 0), babelHelpers.defineProperty(this, "x", void 0), babelHelpers.classPrivateFieldInitSpec(this, _B, void 0), this, (() => { + hasX = o => _x.has(babelHelpers.checkInRHS(o)); + hasA = o => _Class_brand.has(babelHelpers.checkInRHS(o)); + hasM = o => _Class_brand.has(babelHelpers.checkInRHS(o)); + })(), _initClass(); + } +}, babelHelpers.defineProperty(_Class, _Foo2, void 0), _Class)(); +function _get_a(_this) { + return babelHelpers.classPrivateFieldGet2(_A, _Foo); +} +function _set_a(_this2, v) { + babelHelpers.classPrivateFieldSet2(_A, _Foo, v); +} +function _m() {} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/exec.js new file mode 100644 index 000000000000..990f87419c40 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/exec.js @@ -0,0 +1,66 @@ +{ + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, OriginalFoo; + + class Base { + static id(v) { return v; } + } + + class Bar extends Base {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo extends class {} { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method() { + staticThis = super.id(this); + hasX = (o) => #x in o; + getX = (o) => o.#x; + setX = (o, v) => o.#x = v; + hasA = (o) => #a in o; + getA = (o) => o.#a; + setA = (o, v) => o.#a = v; + hasM = (o) => #m in o; + callM = (o) => o.#m(); + }; + + static method() { + Foo.#method() + } + } + + OriginalFoo.method(); + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/input.js new file mode 100644 index 000000000000..b86a95d69cda --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/input.js @@ -0,0 +1,25 @@ +const dec = () => {}; +let hasX, hasA, hasM; + +class Base { + static id(v) { return v; } +} + +@dec +class Foo extends Base { + #x; + accessor #a; + #m() {} + + x; + accessor a; + m() {} + + static #method() { + super.id(this); + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + } +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/options.json new file mode 100644 index 000000000000..56a5af1abb52 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/options.json @@ -0,0 +1,5 @@ +{ + "assumptions": { + "ignoreFunctionLength": true + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/output.js new file mode 100644 index 000000000000..e5763c7bdbbd --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/output.js @@ -0,0 +1,49 @@ +var _Class, _Class_brand, _Foo3, _x, _A, _Foo3_brand, _B; +let _initClass, _method, _Foo2; +const dec = () => {}; +let hasX, hasA, hasM; +class Base { + static id(v) { + return v; + } +} +let _Foo; +new (_Class_brand = /*#__PURE__*/new WeakSet(), _Foo2 = (_x = /*#__PURE__*/new WeakMap(), _A = /*#__PURE__*/new WeakMap(), _Foo3_brand = /*#__PURE__*/new WeakSet(), _B = /*#__PURE__*/new WeakMap(), _Foo3 = class Foo extends Base { + constructor(...args) { + super(...args); + babelHelpers.classPrivateMethodInitSpec(this, _Foo3_brand); + babelHelpers.classPrivateFieldInitSpec(this, _x, void 0); + babelHelpers.classPrivateFieldInitSpec(this, _A, void 0); + babelHelpers.defineProperty(this, "x", void 0); + babelHelpers.classPrivateFieldInitSpec(this, _B, void 0); + } + get a() { + return babelHelpers.classPrivateFieldGet2(_B, this); + } + set a(v) { + babelHelpers.classPrivateFieldSet2(_B, this, v); + } + m() {} +}, (() => { + [_Foo, _initClass] = babelHelpers.applyDecs2311(_Foo3, [dec], [], 0, void 0, Base).c; + _method = function () { + babelHelpers.superPropGet(_Foo, "id", this, 2)([this]); + hasX = o => _x.has(babelHelpers.checkInRHS(o)); + hasA = o => _Foo3_brand.has(babelHelpers.checkInRHS(o)); + hasM = o => _Foo3_brand.has(babelHelpers.checkInRHS(o)); + }; +})(), _Foo3), _Class = class extends babelHelpers.identity { + constructor() { + super(_Foo), babelHelpers.classPrivateMethodInitSpec(this, _Class_brand), this, _initClass(); + } +}, babelHelpers.defineProperty(_Class, _Foo2, void 0), _Class)(); +function _get_a(_this) { + return babelHelpers.classPrivateFieldGet2(_A, _this); +} +function _set_a(_this2, v) { + babelHelpers.classPrivateFieldSet2(_A, _this2, v); +} +function _m() {} +function _method2(...arg) { + return _method.apply(this, arg); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super/exec.js new file mode 100644 index 000000000000..cc74cb04286c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super/exec.js @@ -0,0 +1,68 @@ +{ + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, thisMethodLength, OriginalFoo; + + class Base { + static id(v) { return v; } + } + + class Bar extends Base {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo extends class {} { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method(_) { + staticThis = super.id(this); + thisMethodLength = super.id(this.#method.length); + hasX = super.id((o) => #x in o); + getX = super.id((o) => o.#x); + setX = super.id((o, v) => o.#x = v); + hasA = super.id((o) => #a in o); + getA = super.id((o) => o.#a); + setA = super.id((o, v) => o.#a = v); + hasM = super.id((o) => #m in o); + callM = super.id((o) => o.#m()); + }; + + static method() { + Foo.#method() + } + } + + OriginalFoo.method(); + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); + expect(thisMethodLength).toBe(1); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super/input.js new file mode 100644 index 000000000000..b86a95d69cda --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super/input.js @@ -0,0 +1,25 @@ +const dec = () => {}; +let hasX, hasA, hasM; + +class Base { + static id(v) { return v; } +} + +@dec +class Foo extends Base { + #x; + accessor #a; + #m() {} + + x; + accessor a; + m() {} + + static #method() { + super.id(this); + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + } +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super/output.js new file mode 100644 index 000000000000..9025033d97ff --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-method-private-instance-element-super/output.js @@ -0,0 +1,49 @@ +var _Class, _Class_brand, _Foo3, _x, _A, _Foo3_brand, _B; +let _initClass, _method, _Foo2; +const dec = () => {}; +let hasX, hasA, hasM; +class Base { + static id(v) { + return v; + } +} +let _Foo; +new (_Class_brand = /*#__PURE__*/new WeakSet(), _Foo2 = (_x = /*#__PURE__*/new WeakMap(), _A = /*#__PURE__*/new WeakMap(), _Foo3_brand = /*#__PURE__*/new WeakSet(), _B = /*#__PURE__*/new WeakMap(), _Foo3 = class Foo extends Base { + constructor(...args) { + super(...args); + babelHelpers.classPrivateMethodInitSpec(this, _Foo3_brand); + babelHelpers.classPrivateFieldInitSpec(this, _x, void 0); + babelHelpers.classPrivateFieldInitSpec(this, _A, void 0); + babelHelpers.defineProperty(this, "x", void 0); + babelHelpers.classPrivateFieldInitSpec(this, _B, void 0); + } + get a() { + return babelHelpers.classPrivateFieldGet2(_B, this); + } + set a(v) { + babelHelpers.classPrivateFieldSet2(_B, this, v); + } + m() {} +}, (() => { + [_Foo, _initClass] = babelHelpers.applyDecs2311(_Foo3, [dec], [], 0, void 0, Base).c; + _method = function () { + babelHelpers.superPropGet(_Foo, "id", this, 2)([this]); + hasX = o => _x.has(babelHelpers.checkInRHS(o)); + hasA = o => _Foo3_brand.has(babelHelpers.checkInRHS(o)); + hasM = o => _Foo3_brand.has(babelHelpers.checkInRHS(o)); + }; +})(), _Foo3), _Class = class extends babelHelpers.identity { + constructor() { + super(_Foo), babelHelpers.classPrivateMethodInitSpec(this, _Class_brand), this, _initClass(); + } +}, babelHelpers.defineProperty(_Class, _Foo2, void 0), _Class)(); +function _get_a(_this) { + return babelHelpers.classPrivateFieldGet2(_A, _this); +} +function _set_a(_this2, v) { + babelHelpers.classPrivateFieldSet2(_A, _this2, v); +} +function _m() {} +function _method2() { + return _method.apply(this, arguments); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-environment-super/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-environment-super/exec.js new file mode 100644 index 000000000000..b7b650a062ce --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-environment-super/exec.js @@ -0,0 +1,107 @@ +{ + "different private/super access in a static private method"; + + const dummy = () => {} + + let b; + + const idFactory = (hint) => { + return class { static ["id" + hint](v) { return v } } + } + + class C extends idFactory("C") { #x = "C#x"; } + + const dec = (b) => { + originalB = b; + return C; + } + + class A extends idFactory("A") { + #x = "A#x"; + static *[Symbol.iterator]() { + @dec + class B extends idFactory("B") { + #x = "B#x"; + @(yield super.idA(o => o.#x), dummy) + static *#iter() { + yield super.idC(o => o.#x); + } + static *iter() { + yield* super.idB(C.#iter()); + } + } + b = new originalB(); + yield* originalB.iter(); + } + } + expect([...A].map(fn => fn(b)).join()).toBe("B#x,B#x"); +} + +{ + "different private/super access in a non-decorated static method"; + + let b; + + const idFactory = (hint) => { + return class { static ["id" + hint](v) { return v } } + } + + class C extends idFactory("C") { #x = "C#x"; } + + const dec = (b) => { + originalB = b; + return C; + } + + class A extends idFactory("A") { + #x = "A#x"; + static *[Symbol.iterator]() { + @dec + class B extends idFactory("B") { + #x = "B#x"; + static [(yield super.idA(o => o.#x), Symbol.iterator)] = function* () { + yield (o => o.#x); + } + } + b = new originalB(); + yield* B; + } + } + expect([...A].map(fn => fn(b)).join()).toBe("B#x,B#x"); +} + +{ + "different private/super access in a decorated static method"; + + const dummy = () => {}; + + let b; + + const idFactory = (hint) => { + return class { static ["id" + hint](v) { return v } } + } + + class C extends idFactory("C") { #x = "C#x"; } + + const dec = (b) => { + originalB = b; + return C; + } + + class A extends idFactory("A") { + #x = "A#x"; + static *[Symbol.iterator]() { + @dec + class B extends idFactory("B") { + #x = "B#x"; + @(yield super.idA(o => o.#x), dummy) + static [(yield super.idA(o => o.#x), Symbol.iterator)] = function* () { + yield (o => o.#x); + } + } + b = new originalB(); + yield* B; + } + } + expect([...A].map(fn => fn(b)).join()).toBe("B#x,B#x,B#x"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-access/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-access/exec.js new file mode 100644 index 000000000000..8578d20ef374 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-access/exec.js @@ -0,0 +1,310 @@ +{ + "instance private access in a static block"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static { + staticThis = this; + hasX = (o) => #x in o; + getX = (o) => o.#x; + setX = (o, v) => o.#x = v; + hasA = (o) => #a in o; + getA = (o) => o.#a; + setA = (o, v) => o.#a = v; + hasM = (o) => #m in o; + callM = (o) => o.#m(); + } + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); +} + +{ + "instance private access in a static field initializer"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static field = ( + staticThis = this, + hasX = (o) => #x in o, + getX = (o) => o.#x, + setX = (o, v) => o.#x = v, + hasA = (o) => #a in o, + getA = (o) => o.#a, + setA = (o, v) => o.#a = v, + hasM = (o) => #m in o, + callM = (o) => o.#m() + ); + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); +} + +{ + "instance private access in the body of a static private method"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, thisMethodLength, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method(_) { + staticThis = this; + thisMethodLength = this.#method.length; + hasX = (o) => #x in o; + getX = (o) => o.#x; + setX = (o, v) => o.#x = v; + hasA = (o) => #a in o; + getA = (o) => o.#a; + setA = (o, v) => o.#a = v; + hasM = (o) => #m in o; + callM = (o) => o.#m(); + }; + + static { + this.#method() + } + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); + expect(thisMethodLength).toBe(1); +} + +{ + "instance private access in the params of a static private method"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, thisMethodLength, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method(v = ( + staticThis = this, + thisMethodLength = this.#method.length, + hasX = (o) => #x in o, + getX = (o) => o.#x, + setX = (o, v) => o.#x = v, + hasA = (o) => #a in o, + getA = (o) => o.#a, + setA = (o, v) => o.#a = v, + hasM = (o) => #m in o, + callM = (o) => o.#m() + )) {}; + + static { + this.#method() + } + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); + expect(thisMethodLength).toBe(1); +} + +{ + "instance private access in everywhere mentioned above"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, thisMethodLength, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method({ + [(staticThis = this, thisMethodLength = this.#method.length, getX = (o) => o.#x)]: _ + } = ( + hasM = (o) => #m in o + )) { + hasA = (o) => #a in o; + } + + static { + hasX = (o) => #x in o; + getA = (o) => o.#a; + callM = (o) => o.#m(); + this.#method(); + } + + static #field = ( + setX = (o, v) => o.#x = v, + setA = (o, v) => o.#a = v + ); + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); + expect(thisMethodLength).toBe(1); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-access/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-access/input.js new file mode 100644 index 000000000000..dfaf6bfa2f49 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-access/input.js @@ -0,0 +1,20 @@ +const dec = () => {}; +let hasX, hasA, hasM; + +@dec +class Foo { + #x; + accessor #a; + #m() {} + + x; + accessor a; + m() {} + + static { + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + } +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-access/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-access/output.js new file mode 100644 index 000000000000..84dbe0853a37 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-access/output.js @@ -0,0 +1,39 @@ +var _Class, _Foo3, _x, _A, _Foo3_brand, _B; +let _initClass, _staticBlock, _Foo2; +const dec = () => {}; +let hasX, hasA, hasM; +let _Foo; +new (_Foo2 = (_x = /*#__PURE__*/new WeakMap(), _A = /*#__PURE__*/new WeakMap(), _Foo3_brand = /*#__PURE__*/new WeakSet(), _B = /*#__PURE__*/new WeakMap(), _Foo3 = class Foo { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Foo3_brand); + babelHelpers.classPrivateFieldInitSpec(this, _x, void 0); + babelHelpers.classPrivateFieldInitSpec(this, _A, void 0); + babelHelpers.defineProperty(this, "x", void 0); + babelHelpers.classPrivateFieldInitSpec(this, _B, void 0); + } + get a() { + return babelHelpers.classPrivateFieldGet2(_B, this); + } + set a(v) { + babelHelpers.classPrivateFieldSet2(_B, this, v); + } + m() {} +}, (() => { + [_Foo, _initClass] = babelHelpers.applyDecs2311(_Foo3, [dec], []).c; + _staticBlock = function () { + hasX = o => _x.has(babelHelpers.checkInRHS(o)); + hasA = o => _Foo3_brand.has(babelHelpers.checkInRHS(o)); + hasM = o => _Foo3_brand.has(babelHelpers.checkInRHS(o)); + }; +})(), _Foo3), _Class = class extends babelHelpers.identity { + constructor() { + super(_Foo), _staticBlock.call(this), _initClass(); + } +}, babelHelpers.defineProperty(_Class, _Foo2, void 0), _Class)(); +function _get_a(_this) { + return babelHelpers.classPrivateFieldGet2(_A, _this); +} +function _set_a(_this2, v) { + babelHelpers.classPrivateFieldSet2(_A, _this2, v); +} +function _m() {} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/exec.js new file mode 100644 index 000000000000..f7c3bbc3f428 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/exec.js @@ -0,0 +1,33 @@ +{ + "instance private destructuring in a static block"; + let getX, getA, callM, staticThis, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x = "#x"; + accessor #a = "#a"; + #m() { return "#m" } + + static { + staticThis = this; + getX = ({ #x: x }) => x; + getA = ({ #a: a }) => a; + callM = ({ #m: m }) => m(); + } + } + + const foo = new OriginalFoo(); + + expect(getX(foo)).toBe("#x"); + expect(getA(foo)).toBe("#a"); + expect(callM(foo)).toBe("#m"); + + expect(staticThis).toBe(Bar); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/input.js new file mode 100644 index 000000000000..1af597aab08d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/input.js @@ -0,0 +1,17 @@ +const dec = () => {}; +let getX, getA, callM; + +@dec +class Foo { + #x = "#x"; + accessor #a = "#a"; + #m() { return "#m" } + + static { + staticThis = this; + getX = ({ #x: x }) => x; + getA = ({ #a: a }) => a; + callM = ({ #m: m }) => m(); + } +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/options.json new file mode 100644 index 000000000000..0cf9369600cc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "proposal-destructuring-private", + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/output.js new file mode 100644 index 000000000000..5a341e6180fe --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-private-instance-element-destructuring/output.js @@ -0,0 +1,42 @@ +var _Class, _Foo3, _x, _A, _Foo3_brand; +let _initClass, _staticBlock, _Foo2; +const dec = () => {}; +let getX, getA, callM; +let _Foo; +new (_Foo2 = (_x = /*#__PURE__*/new WeakMap(), _A = /*#__PURE__*/new WeakMap(), _Foo3_brand = /*#__PURE__*/new WeakSet(), _Foo3 = class Foo { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Foo3_brand); + babelHelpers.classPrivateFieldInitSpec(this, _x, "#x"); + babelHelpers.classPrivateFieldInitSpec(this, _A, "#a"); + } +}, (() => { + [_Foo, _initClass] = babelHelpers.applyDecs2311(_Foo3, [dec], []).c; + _staticBlock = function () { + staticThis = this; + getX = _p => { + var x = babelHelpers.classPrivateFieldGet2(_x, _p); + return x; + }; + getA = _p2 => { + var a = babelHelpers.classPrivateGetter(_Foo3_brand, _p2, _get_a); + return a; + }; + callM = _p3 => { + var m = babelHelpers.assertClassBrand(_Foo3_brand, _p3, _m); + return m(); + }; + }; +})(), _Foo3), _Class = class extends babelHelpers.identity { + constructor() { + super(_Foo), _staticBlock.call(this), _initClass(); + } +}, babelHelpers.defineProperty(_Class, _Foo2, void 0), _Class)(); +function _get_a(_this) { + return babelHelpers.classPrivateFieldGet2(_A, _this); +} +function _set_a(_this2, v) { + babelHelpers.classPrivateFieldSet2(_A, _this2, v); +} +function _m() { + return "#m"; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-this/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-this/exec.js new file mode 100644 index 000000000000..6b55df43edc8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-this/exec.js @@ -0,0 +1,19 @@ + +class Bar {} + +let _this, _this2, _this3; + +@(() => Bar) +class Foo { + static { + _this = this; + } + static field = (_this2 = this); + static { + _this3 = this; + } +} + +expect(_this).toBe(Bar); +expect(_this2).toBe(Bar); +expect(_this3).toBe(Bar); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-this/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-this/input.js new file mode 100644 index 000000000000..1b8d46cf3ac0 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-this/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +@dec +class Foo { + static { + this + } + static field = this; + static { + this + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-this/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-this/output.js new file mode 100644 index 000000000000..3671ef32d5e9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-static-this/output.js @@ -0,0 +1,13 @@ +var _Class, _Foo3; +let _initClass, _Foo2; +const dec = () => {}; +let _Foo; +new (_Foo2 = (_Foo3 = class Foo {}, [_Foo, _initClass] = babelHelpers.applyDecs2311(_Foo3, [dec], []).c, _Foo3), _Class = class extends babelHelpers.identity { + constructor() { + super(_Foo), babelHelpers.defineProperty(this, "field", ((() => { + this; + })(), this)), (() => { + this; + })(), _initClass(); + } +}, babelHelpers.defineProperty(_Class, _Foo2, void 0), _Class)(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-with-expr/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-with-expr/exec.js new file mode 100644 index 000000000000..739e33a05be5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-with-expr/exec.js @@ -0,0 +1,17 @@ +let replaced; + +function dec(Klass) { + replaced = class extends Klass {}; + + return replaced; +} + +const Foo = @dec class Bar { + static bar = new Bar(); +}; + +const foo = new Foo(); + +expect(Foo).toBe(replaced); +expect(Foo.bar).toBeInstanceOf(replaced); +expect(foo).toBeInstanceOf(replaced); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-with-expr/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-with-expr/input.js new file mode 100644 index 000000000000..0cd5e45110b7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-with-expr/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +const Foo = @dec class Bar { + bar = new Bar(); +}; + +const foo = new Foo(); + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-with-expr/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-with-expr/output.js new file mode 100644 index 000000000000..dad94690af85 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement-with-expr/output.js @@ -0,0 +1,9 @@ +var _Bar2; +let _initClass, _Bar; +const dec = () => {}; +const Foo = (_Bar2 = class Bar { + constructor() { + babelHelpers.defineProperty(this, "bar", new _Bar()); + } +}, [_Bar, _initClass] = babelHelpers.applyDecs2311(_Bar2, [dec], []).c, _initClass(), _Bar); +const foo = new Foo(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement/exec.js new file mode 100644 index 000000000000..c8dc49c0d85e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement/exec.js @@ -0,0 +1,19 @@ + +let replaced; + +function dec(Klass) { + replaced = class extends Klass {}; + + return replaced; +} + +@dec +class Foo { + static foo = new Foo(); +} + +const foo = new Foo(); + +expect(Foo).toBe(replaced); +expect(Foo.foo).toBeInstanceOf(replaced); +expect(foo).toBeInstanceOf(replaced); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement/input.js new file mode 100644 index 000000000000..8f0a4dfe092f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +@dec +class Foo { + static foo = new Foo(); +} + +const foo = new Foo(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement/output.js new file mode 100644 index 000000000000..ff3e509ea8b3 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes--to-es2015/replacement/output.js @@ -0,0 +1,10 @@ +var _Class, _Foo3; +let _initClass, _Foo2; +const dec = () => {}; +let _Foo; +new (_Foo2 = (_Foo3 = class Foo {}, [_Foo, _initClass] = babelHelpers.applyDecs2311(_Foo3, [dec], []).c, _Foo3), _Class = class extends babelHelpers.identity { + constructor() { + super(_Foo), babelHelpers.defineProperty(this, "foo", new _Foo()), _initClass(); + } +}, babelHelpers.defineProperty(_Class, _Foo2, void 0), _Class)(); +const foo = new _Foo(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/ctx/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/ctx/exec.js new file mode 100644 index 000000000000..ec0949c1390b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/ctx/exec.js @@ -0,0 +1,9 @@ +const logs = []; +function dec(value, ctx) { + logs.push(ctx.kind, ctx.name); +} + +@dec +class A {} + +expect(logs).toEqual(["class", "A"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/ctx/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/ctx/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/ctx/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-classes/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-classes/exec.js new file mode 100644 index 000000000000..2bfa992f5a3a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-classes/exec.js @@ -0,0 +1,23 @@ +function decorateA(target) { + return class extends target { + a() { + return "a"; + } + }; +} + +function decorateB(target) { + return class extends target { + b() { + return "b"; + } + }; +} + +@decorateB +@decorateA +class Target {} + +const target = new Target(); +expect(target.a()).toBe("a"); +expect(target.b()).toBe("b"); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-classes/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-classes/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-classes/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/exec.js new file mode 100644 index 000000000000..9d5c4bbf3d15 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/exec.js @@ -0,0 +1,14 @@ +var value; +const classDec = (Class) => { + value = (new Class).m; + return Class +}; + +const memberDec = () => () => 42; + +@classDec +class C { + @memberDec m; +} + +expect(value).toBe(42); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/input.js new file mode 100644 index 000000000000..8689cf13f9e5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/input.js @@ -0,0 +1,12 @@ +var value; +const classDec = (Class) => { + value = (new Class).p; + return Class +}; + +const memberDec = () => () => 42; + +@classDec +class C { + @memberDec m; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/output.js new file mode 100644 index 000000000000..f94d21a5c0ed --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/output.js @@ -0,0 +1,23 @@ +let _initClass, _init_m, _init_extra_m; +var value; +const classDec = Class => { + value = new Class().p; + return Class; +}; +const memberDec = () => () => 42; +let _C; +class C { + static { + ({ + e: [_init_m, _init_extra_m], + c: [_C, _initClass] + } = babelHelpers.applyDecs2311(this, [classDec], [[memberDec, 0, "m"]])); + } + constructor() { + _init_extra_m(this); + } + m = _init_m(this); + static { + _initClass(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/exec.js new file mode 100644 index 000000000000..a85569beafbc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/exec.js @@ -0,0 +1,14 @@ +var value; +const classDec = (Class) => { + value = (new Class).m(); + return Class +}; + +const memberDec = () => () => 42; + +@classDec +class C { + @memberDec m() {}; +} + +expect(value).toBe(42); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/input.js new file mode 100644 index 000000000000..7d8094583001 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/input.js @@ -0,0 +1,12 @@ +var value; +const classDec = (Class) => { + value = (new Class).m(); + return Class +}; + +const memberDec = () => () => 42; + +@classDec +class C { + @memberDec m() {}; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/output.js new file mode 100644 index 000000000000..e10cc23cdf83 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/output.js @@ -0,0 +1,23 @@ +let _initProto, _initClass; +var value; +const classDec = Class => { + value = new Class().m(); + return Class; +}; +const memberDec = () => () => 42; +let _C; +class C { + static { + ({ + e: [_initProto], + c: [_C, _initClass] + } = babelHelpers.applyDecs2311(this, [classDec], [[memberDec, 2, "m"]])); + } + constructor() { + _initProto(this); + } + m() {} + static { + _initClass(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-named-evaluation/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-named-evaluation/exec.js new file mode 100644 index 000000000000..6aa8c3235b73 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-named-evaluation/exec.js @@ -0,0 +1,209 @@ +// prettier-ignore +const logs = []; +const decFactory = (logs) => (value, context) => { + expect(value.name).toEqual(context.name); + logs.push(context.name); + return value; +}; +const dec = decFactory(logs); + +export default @dec class {} + +export const atypical = @dec class {} + +expect(logs).toEqual(["default", "atypical"]); + +const noop = () => {} + +{ + const logs = []; + const dec = decFactory(logs); + + var A0 = @dec class {}; + let A1 = @dec class { static {} }; + const A2 = @dec class extends A1 {} + + expect(logs).toEqual(["A0", "A1", "A2"]); +} + +{ + const logs = []; + const dec = decFactory(logs); + const f = () => { logs.push("computing f"); return 8. } + + ({ + A0: @dec class {}, + "1": @dec class { static {} }, + 2: @dec class extends class {} {}, + 3n: @dec class extends class {} { static {} }, + ["4"]: @dec class { p; }, + [5]: @dec class { p; }, + [6n]: @dec class { p; }, + [f()]: @dec class { @dec static 7() {} }, + [{ [Symbol.toPrimitive]: () => (logs.push("computing symbol"), Symbol(9)) }]: @dec class { p; } + }); + + expect(logs).toEqual(["A0", "1", "2", "3", "4", "5", "6", "computing f", "7", "8", "computing symbol", "[9]"]); +} + +{ + const logs = []; + const dec = decFactory(logs); + const f = () => { logs.push("computing f"); return 8. } + + class C { + A0 = @dec class {}; + "1" = @dec class { static {} }; + 2 = @dec class extends class {} {}; + 3n = @dec class extends class {} { static {} }; + ["4"] = @dec class { p; }; + [5] = @dec class { p; }; + [6n] = @dec class { p; }; + [f()] = @dec class { @dec static 7() {} }; + [{ [Symbol.toPrimitive]: () => (logs.push("computing symbol"), Symbol(9)) }] = @dec class { p; }; + #_10 = @dec class {}; + } + + new C(); + + expect(logs).toEqual(["computing f", "computing symbol", "A0", "1", "2", "3", "4", "5", "6", "7", "8", "[9]", "#_10"]); +} + +{ + const logs = []; + const dec = decFactory(logs); + const f = () => { logs.push("computing f"); return 8. } + + class C { + static A0 = @dec class {}; + static "1" = @dec class { static {} }; + static 2 = @dec class extends class {} {}; + static 3n = @dec class extends class {} { static {} }; + static ["4"] = @dec class { p; }; + static [5] = @dec class { p; }; + static [6n] = @dec class { p; }; + static [f()] = @dec class { @dec static 7() {} }; + static [{ [Symbol.toPrimitive]: () => (logs.push("computing symbol"), Symbol(9)) }] = @dec class { p; }; + static #_10 = @dec class {}; + } + + expect(logs).toEqual(["computing f", "computing symbol", "A0", "1", "2", "3", "4", "5", "6", "7", "8", "[9]", "#_10"]); +} + +{ + const logs = []; + const dec = decFactory(logs); + const f = () => { logs.push("computing f"); return 8. } + + class C { + accessor A0 = @dec class {}; + accessor "1" = @dec class { static {} }; + accessor 2 = @dec class extends class {} {}; + accessor 3n = @dec class extends class {} { static {} }; + accessor ["4"] = @dec class { p; }; + accessor [5] = @dec class { p; }; + accessor [6n] = @dec class { p; }; + accessor [f()] = @dec class { @dec static 7() {} }; + accessor [{ [Symbol.toPrimitive]: () => (logs.push("computing symbol"), Symbol(9)) }] = @dec class { p; }; + accessor #_10 = @dec class {}; + } + + new C(); + + expect(logs).toEqual(["computing f", "computing symbol", "A0", "1", "2", "3", "4", "5", "6", "7", "8", "[9]", "#_10"]); +} + +{ + const logs = []; + const dec = decFactory(logs); + const f = () => { logs.push("computing f"); return 8. } + + class C { + static accessor A0 = @dec class {}; + static accessor "1" = @dec class { static {} }; + static accessor 2 = @dec class extends class {} {}; + static accessor 3n = @dec class extends class {} { static {} }; + static accessor ["4"] = @dec class { p; }; + static accessor [5] = @dec class { p; }; + static accessor [6n] = @dec class { p; }; + static accessor [f()] = @dec class { @dec static 7() {} }; + static accessor [{ [Symbol.toPrimitive]: () => (logs.push("computing symbol"), Symbol(9)) }] = @dec class { p; }; + static accessor #_10 = @dec class {}; + } + + expect(logs).toEqual(["computing f", "computing symbol", "A0", "1", "2", "3", "4", "5", "6", "7", "8", "[9]", "#_10"]); +} + +{ + const logs = []; + const dec = decFactory(logs); + const f = () => { logs.push("computing f"); return 8. } + + class C { + static accessor A0 = @dec class {}; + static accessor "1" = @dec class { static {} }; + static accessor 2 = @dec class extends class {} {}; + static accessor 3n = @dec class extends class {} { static {} }; + static accessor ["4"] = @dec class { static accessor p; }; + static accessor [5] = @dec class { @noop static accessor #p; }; + static accessor [6n] = @dec class { accessor p; }; + static accessor [f()] = @dec class { @dec static 7() {} }; + static accessor [{ [Symbol.toPrimitive]: () => (logs.push("computing symbol"), Symbol(9)) }] = @dec class { @noop accessor p; }; + static accessor #_10 = @dec class {}; + } + + expect(logs).toEqual(["computing f", "computing symbol", "A0", "1", "2", "3", "4", "5", "6", "7", "8", "[9]", "#_10"]); +} + +{ + const logs = []; + const dec = () => { + return { + init(v) { + logs.push(v.name); + return v; + } + } + }; + const f = () => { logs.push("computing f"); return 8. } + + class C { + @dec static accessor A0 = class { static accessor q; }; + @dec static accessor "1" = class { accessor q; }; + @dec static accessor 2 = class extends class {} { static accessor p; }; + @dec static accessor 3n = class extends class {} { accessor #q; }; + @dec static accessor ["4"] = class { static accessor p; }; + @dec static accessor [5] = class { static accessor #p; }; + @dec static accessor [6n] = class { accessor p; }; + @dec static accessor [f()] = class { @dec static accessor 7 = class { static accessor p }; }; + @dec static accessor [{ [Symbol.toPrimitive]: () => (logs.push("computing symbol"), Symbol(9)) }] = class { static accessor p; }; + @dec static accessor #_10 = class { static accessor #p; }; + } + + expect(logs).toEqual(["computing f", "computing symbol", "A0", "1", "2", "3", "4", "5", "6", "7", "8", "[9]", "#_10"]); +} + +{ + const logs = []; + const dec = decFactory(logs); + // __proto__ setter should not name anonymous class + ({ + __proto__: @dec class {}, + }); + ({ + "__proto__": @dec class {}, + }); + expect(logs).toEqual(["", ""]); +} + +{ + const logs = []; + const dec = decFactory(logs); + // __proto__ has no special meaning in class fields + class A extends class { + static __proto__ = @dec class {} + } { + static "__proto__" = @dec class {} + } + expect(logs).toEqual(["__proto__", "__proto__"]); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-named-evaluation/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-named-evaluation/options.json new file mode 100644 index 000000000000..44c419fff9b7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-named-evaluation/options.json @@ -0,0 +1,8 @@ +{ + "sourceType": "module", + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-modules-commonjs" + ], + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-static-blocks/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-static-blocks/input.js new file mode 100644 index 000000000000..853ac0e6a43b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-static-blocks/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +const A = @dec class A { static {} } +const B = @dec class C { static {} } +const D = @dec class { static {} } +const E = (@dec class { static {} }, 123); +const F = [@dec class G { static {} }, @dec class { static {} }]; +const H = @dec class extends I { static {} }; +const J = @dec class K extends L { static {} }; + +function classFactory() { + return @dec class { static {} } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-static-blocks/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-static-blocks/output.js new file mode 100644 index 000000000000..6a59cb3625d2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions-static-blocks/output.js @@ -0,0 +1,95 @@ +var _I, _L; +let _initClass, _A, _initClass2, _C, _initClass3, _D, _initClass4, _decorated_class, _initClass5, _G, _initClass6, _decorated_class2, _initClass7, _H, _initClass8, _K; +const dec = () => {}; +const A = (new class extends babelHelpers.identity { + static [class A { + static { + [_A, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + constructor() { + super(_A), (() => {})(), _initClass(); + } +}(), _A); +const B = (new class extends babelHelpers.identity { + static [class C { + static { + [_C, _initClass2] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + constructor() { + super(_C), (() => {})(), _initClass2(); + } +}(), _C); +const D = (new class extends babelHelpers.identity { + static [class D { + static { + [_D, _initClass3] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + constructor() { + super(_D), (() => {})(), _initClass3(); + } +}(), _D); +const E = (new class extends babelHelpers.identity { + static [class { + static { + [_decorated_class, _initClass4] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + constructor() { + super(_decorated_class), (() => {})(), _initClass4(); + } +}(), _decorated_class, 123); +const F = [(new class extends babelHelpers.identity { + static [class G { + static { + [_G, _initClass5] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + constructor() { + super(_G), (() => {})(), _initClass5(); + } +}(), _G), (new class extends babelHelpers.identity { + static [class { + static { + [_decorated_class2, _initClass6] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + constructor() { + super(_decorated_class2), (() => {})(), _initClass6(); + } +}(), _decorated_class2)]; +const H = (new class extends babelHelpers.identity { + static [class H extends (_I = I) { + static { + [_H, _initClass7] = babelHelpers.applyDecs2311(this, [dec], [], 0, void 0, _I).c; + } + }]; + constructor() { + super(_H), (() => {})(), _initClass7(); + } +}(), _H); +const J = (new class extends babelHelpers.identity { + static [class K extends (_L = L) { + static { + [_K, _initClass8] = babelHelpers.applyDecs2311(this, [dec], [], 0, void 0, _L).c; + } + }]; + constructor() { + super(_K), (() => {})(), _initClass8(); + } +}(), _K); +function classFactory() { + let _initClass9, _decorated_class3; + return new class extends babelHelpers.identity { + static [class { + static { + [_decorated_class3, _initClass9] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + constructor() { + super(_decorated_class3), (() => {})(), _initClass9(); + } + }(), _decorated_class3; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions/input.js new file mode 100644 index 000000000000..77060bea50ff --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +const A = @dec class A {} +const B = @dec class C {} +const D = @dec class {} +const E = (@dec class {}, 123); +const F = [@dec class G {}, @dec class {}]; +const H = @dec class extends I {}; +const J = @dec class K extends L {}; + +function classFactory() { + return @dec class {} +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions/output.js new file mode 100644 index 000000000000..15eca62d4e67 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/expressions/output.js @@ -0,0 +1,77 @@ +var _I, _L; +let _initClass, _A, _initClass2, _C, _initClass3, _D, _initClass4, _decorated_class, _initClass5, _G, _initClass6, _decorated_class2, _initClass7, _H, _initClass8, _K; +const dec = () => {}; +const A = (class A { + static { + [_A, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static { + _initClass(); + } +}, _A); +const B = (class C { + static { + [_C, _initClass2] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static { + _initClass2(); + } +}, _C); +const D = (class D { + static { + [_D, _initClass3] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static { + _initClass3(); + } +}, _D); +const E = (class { + static { + [_decorated_class, _initClass4] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static { + _initClass4(); + } +}, _decorated_class, 123); +const F = [(class G { + static { + [_G, _initClass5] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static { + _initClass5(); + } +}, _G), (class { + static { + [_decorated_class2, _initClass6] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static { + _initClass6(); + } +}, _decorated_class2)]; +const H = (class H extends (_I = I) { + static { + [_H, _initClass7] = babelHelpers.applyDecs2311(this, [dec], [], 0, void 0, _I).c; + } + static { + _initClass7(); + } +}, _H); +const J = (class K extends (_L = L) { + static { + [_K, _initClass8] = babelHelpers.applyDecs2311(this, [dec], [], 0, void 0, _L).c; + } + static { + _initClass8(); + } +}, _K); +function classFactory() { + let _initClass9, _decorated_class3; + return class { + static { + [_decorated_class3, _initClass9] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static { + _initClass9(); + } + }, _decorated_class3; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/inheritance/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/inheritance/input.js new file mode 100644 index 000000000000..0657f6e2b364 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/inheritance/input.js @@ -0,0 +1,6 @@ +const dec = () => {}; +@dec1 +class Bar {} + +@dec2 +class Foo extends Bar {} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/inheritance/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/inheritance/output.js new file mode 100644 index 000000000000..c90e86707bf9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/inheritance/output.js @@ -0,0 +1,21 @@ +var _Bar2; +let _initClass, _initClass2; +const dec = () => {}; +let _Bar; +class Bar { + static { + [_Bar, _initClass] = babelHelpers.applyDecs2311(this, [dec1], []).c; + } + static { + _initClass(); + } +} +let _Foo; +class Foo extends (_Bar2 = _Bar) { + static { + [_Foo, _initClass2] = babelHelpers.applyDecs2311(this, [dec2], [], 0, void 0, _Bar2).c; + } + static { + _initClass2(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/initializers/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/initializers/input.js new file mode 100644 index 000000000000..87c785d39a93 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/initializers/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +@dec +class Foo { + static field = 123; +} + +@dec +class Bar extends Foo { + static { + this.otherField = 456; + } + + static field = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/initializers/output.js new file mode 100644 index 000000000000..ff4e179e1c12 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/initializers/output.js @@ -0,0 +1,29 @@ +var _Foo2; +let _initClass, _initClass2; +const dec = () => {}; +let _Foo; +new class extends babelHelpers.identity { + static [class Foo { + static { + [_Foo, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + field = 123; + constructor() { + super(_Foo), _initClass(); + } +}(); +let _Bar; +new class extends babelHelpers.identity { + static [class Bar extends (_Foo2 = _Foo) { + static { + [_Bar, _initClass2] = babelHelpers.applyDecs2311(this, [dec], [], 0, void 0, _Foo2).c; + } + }]; + field = ((() => { + this.otherField = 456; + })(), 123); + constructor() { + super(_Bar), _initClass2(); + } +}(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/options.json new file mode 100644 index 000000000000..154ee22b969c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/options.json @@ -0,0 +1,4 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]], + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-decorator-initializer-this/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-decorator-initializer-this/input.js new file mode 100644 index 000000000000..d6335133be0e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-decorator-initializer-this/input.js @@ -0,0 +1,35 @@ + +let original, replaced, accessorThis, getterThis, setterThis, methodThis, propertyThis, classThis; + +function dec(Klass, context) { + original = Klass; + replaced = class extends Klass {}; + + context.addInitializer(function () { + classThis = this; + }) + + return replaced; +} + +function captureInitializerThis(callback) { + return function (_, context) { + context.addInitializer(function () { + callback(this); + }) + } +} + +@dec +class Foo { + @(captureInitializerThis(v => accessorThis = v)) + static accessor accessor; + @(captureInitializerThis(v => getterThis = v)) + static get getter() {}; + @(captureInitializerThis(v => setterThis = v)) + static set setter(_) {}; + @(captureInitializerThis(v => methodThis = v)) + static method() {} + @(captureInitializerThis(v => propertyThis = v)) + static property; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-decorator-initializer-this/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-decorator-initializer-this/output.js new file mode 100644 index 000000000000..6d9f4bd24d31 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-decorator-initializer-this/output.js @@ -0,0 +1,45 @@ +let _initStatic, _initClass, _init_accessor, _init_extra_accessor, _init_property, _init_extra_property; +let original, replaced, accessorThis, getterThis, setterThis, methodThis, propertyThis, classThis; +function dec(Klass, context) { + original = Klass; + replaced = class extends Klass {}; + context.addInitializer(function () { + classThis = this; + }); + return replaced; +} +function captureInitializerThis(callback) { + return function (_, context) { + context.addInitializer(function () { + callback(this); + }); + }; +} +let _Foo; +new class extends babelHelpers.identity { + static [class Foo { + static { + ({ + e: [_init_accessor, _init_extra_accessor, _init_property, _init_extra_property, _initStatic], + c: [_Foo, _initClass] + } = babelHelpers.applyDecs2311(this, [dec], [[captureInitializerThis(v => accessorThis = v), 9, "accessor"], [captureInitializerThis(v => getterThis = v), 11, "getter"], [captureInitializerThis(v => setterThis = v), 12, "setter"], [captureInitializerThis(v => methodThis = v), 10, "method"], [captureInitializerThis(v => propertyThis = v), 8, "property"]])); + _initStatic(this); + } + static get accessor() { + return Foo.#A; + } + static set accessor(v) { + Foo.#A = v; + } + static get getter() {} + static set setter(_) {} + static method() {} + }]; + #A = _init_accessor(); + property = (_init_extra_accessor(), _init_property()); + constructor() { + super(_Foo), (() => { + _init_extra_property(); + })(), _initClass(); + } +}(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-installed-on-correct-class/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-installed-on-correct-class/input.js new file mode 100644 index 000000000000..c62f272ff354 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-installed-on-correct-class/input.js @@ -0,0 +1,19 @@ +const dec = () => {}; +let hasX, hasA, hasM; + +@dec +class Foo { + static #x; + static accessor #a; + static #m() {} + + static x; + static accessor a; + static m() {} + + static { + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-installed-on-correct-class/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-installed-on-correct-class/output.js new file mode 100644 index 000000000000..1fe42bddb2a4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-installed-on-correct-class/output.js @@ -0,0 +1,36 @@ +let _initClass; +const dec = () => {}; +let hasX, hasA, hasM; +let _Foo; +new class extends babelHelpers.identity { + static [class Foo { + static { + [_Foo, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static get a() { + return _Foo.#B; + } + static set a(v) { + _Foo.#B = v; + } + static m() {} + }]; + #x; + #A; + get #a() { + return _Foo.#A; + } + set #a(v) { + _Foo.#A = v; + } + #m() {} + x; + #B; + constructor() { + super(_Foo), (() => { + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + })(), _initClass(); + } +}(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/exec.js new file mode 100644 index 000000000000..990f87419c40 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/exec.js @@ -0,0 +1,66 @@ +{ + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, OriginalFoo; + + class Base { + static id(v) { return v; } + } + + class Bar extends Base {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo extends class {} { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method() { + staticThis = super.id(this); + hasX = (o) => #x in o; + getX = (o) => o.#x; + setX = (o, v) => o.#x = v; + hasA = (o) => #a in o; + getA = (o) => o.#a; + setA = (o, v) => o.#a = v; + hasM = (o) => #m in o; + callM = (o) => o.#m(); + }; + + static method() { + Foo.#method() + } + } + + OriginalFoo.method(); + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/input.js new file mode 100644 index 000000000000..b86a95d69cda --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/input.js @@ -0,0 +1,25 @@ +const dec = () => {}; +let hasX, hasA, hasM; + +class Base { + static id(v) { return v; } +} + +@dec +class Foo extends Base { + #x; + accessor #a; + #m() {} + + x; + accessor a; + m() {} + + static #method() { + super.id(this); + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + } +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/options.json new file mode 100644 index 000000000000..56a5af1abb52 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/options.json @@ -0,0 +1,5 @@ +{ + "assumptions": { + "ignoreFunctionLength": true + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/output.js new file mode 100644 index 000000000000..99b1fa5e8a73 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super-assumption-ignoreFunctionLength/output.js @@ -0,0 +1,46 @@ +let _initClass, _method; +const dec = () => {}; +let hasX, hasA, hasM; +class Base { + static id(v) { + return v; + } +} +let _Foo; +new class extends babelHelpers.identity { + static [class Foo extends Base { + static { + [_Foo, _initClass] = babelHelpers.applyDecs2311(this, [dec], [], 0, void 0, Base).c; + _method = function () { + babelHelpers.superPropGet(_Foo, "id", this, 2)([this]); + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + }; + } + #x; + #A; + get #a() { + return this.#A; + } + set #a(v) { + this.#A = v; + } + #m() {} + x; + #B; + get a() { + return this.#B; + } + set a(v) { + this.#B = v; + } + m() {} + }]; + #method(...arg) { + return _method.apply(this, arg); + } + constructor() { + super(_Foo), _initClass(); + } +}(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super/exec.js new file mode 100644 index 000000000000..cc74cb04286c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super/exec.js @@ -0,0 +1,68 @@ +{ + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, thisMethodLength, OriginalFoo; + + class Base { + static id(v) { return v; } + } + + class Bar extends Base {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo extends class {} { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method(_) { + staticThis = super.id(this); + thisMethodLength = super.id(this.#method.length); + hasX = super.id((o) => #x in o); + getX = super.id((o) => o.#x); + setX = super.id((o, v) => o.#x = v); + hasA = super.id((o) => #a in o); + getA = super.id((o) => o.#a); + setA = super.id((o, v) => o.#a = v); + hasM = super.id((o) => #m in o); + callM = super.id((o) => o.#m()); + }; + + static method() { + Foo.#method() + } + } + + OriginalFoo.method(); + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); + expect(thisMethodLength).toBe(1); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super/input.js new file mode 100644 index 000000000000..b86a95d69cda --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super/input.js @@ -0,0 +1,25 @@ +const dec = () => {}; +let hasX, hasA, hasM; + +class Base { + static id(v) { return v; } +} + +@dec +class Foo extends Base { + #x; + accessor #a; + #m() {} + + x; + accessor a; + m() {} + + static #method() { + super.id(this); + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + } +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super/output.js new file mode 100644 index 000000000000..ca2d72306b9d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-method-private-instance-element-super/output.js @@ -0,0 +1,46 @@ +let _initClass, _method; +const dec = () => {}; +let hasX, hasA, hasM; +class Base { + static id(v) { + return v; + } +} +let _Foo; +new class extends babelHelpers.identity { + static [class Foo extends Base { + static { + [_Foo, _initClass] = babelHelpers.applyDecs2311(this, [dec], [], 0, void 0, Base).c; + _method = function () { + babelHelpers.superPropGet(_Foo, "id", this, 2)([this]); + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + }; + } + #x; + #A; + get #a() { + return this.#A; + } + set #a(v) { + this.#A = v; + } + #m() {} + x; + #B; + get a() { + return this.#B; + } + set a(v) { + this.#B = v; + } + m() {} + }]; + #method() { + return _method.apply(this, arguments); + } + constructor() { + super(_Foo), _initClass(); + } +}(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-environment-super/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-environment-super/exec.js new file mode 100644 index 000000000000..b7b650a062ce --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-environment-super/exec.js @@ -0,0 +1,107 @@ +{ + "different private/super access in a static private method"; + + const dummy = () => {} + + let b; + + const idFactory = (hint) => { + return class { static ["id" + hint](v) { return v } } + } + + class C extends idFactory("C") { #x = "C#x"; } + + const dec = (b) => { + originalB = b; + return C; + } + + class A extends idFactory("A") { + #x = "A#x"; + static *[Symbol.iterator]() { + @dec + class B extends idFactory("B") { + #x = "B#x"; + @(yield super.idA(o => o.#x), dummy) + static *#iter() { + yield super.idC(o => o.#x); + } + static *iter() { + yield* super.idB(C.#iter()); + } + } + b = new originalB(); + yield* originalB.iter(); + } + } + expect([...A].map(fn => fn(b)).join()).toBe("B#x,B#x"); +} + +{ + "different private/super access in a non-decorated static method"; + + let b; + + const idFactory = (hint) => { + return class { static ["id" + hint](v) { return v } } + } + + class C extends idFactory("C") { #x = "C#x"; } + + const dec = (b) => { + originalB = b; + return C; + } + + class A extends idFactory("A") { + #x = "A#x"; + static *[Symbol.iterator]() { + @dec + class B extends idFactory("B") { + #x = "B#x"; + static [(yield super.idA(o => o.#x), Symbol.iterator)] = function* () { + yield (o => o.#x); + } + } + b = new originalB(); + yield* B; + } + } + expect([...A].map(fn => fn(b)).join()).toBe("B#x,B#x"); +} + +{ + "different private/super access in a decorated static method"; + + const dummy = () => {}; + + let b; + + const idFactory = (hint) => { + return class { static ["id" + hint](v) { return v } } + } + + class C extends idFactory("C") { #x = "C#x"; } + + const dec = (b) => { + originalB = b; + return C; + } + + class A extends idFactory("A") { + #x = "A#x"; + static *[Symbol.iterator]() { + @dec + class B extends idFactory("B") { + #x = "B#x"; + @(yield super.idA(o => o.#x), dummy) + static [(yield super.idA(o => o.#x), Symbol.iterator)] = function* () { + yield (o => o.#x); + } + } + b = new originalB(); + yield* B; + } + } + expect([...A].map(fn => fn(b)).join()).toBe("B#x,B#x,B#x"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-environment-super/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-environment-super/options.json new file mode 100644 index 000000000000..947b7731cb78 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-environment-super/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "18.0.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-access/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-access/exec.js new file mode 100644 index 000000000000..8578d20ef374 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-access/exec.js @@ -0,0 +1,310 @@ +{ + "instance private access in a static block"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static { + staticThis = this; + hasX = (o) => #x in o; + getX = (o) => o.#x; + setX = (o, v) => o.#x = v; + hasA = (o) => #a in o; + getA = (o) => o.#a; + setA = (o, v) => o.#a = v; + hasM = (o) => #m in o; + callM = (o) => o.#m(); + } + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); +} + +{ + "instance private access in a static field initializer"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static field = ( + staticThis = this, + hasX = (o) => #x in o, + getX = (o) => o.#x, + setX = (o, v) => o.#x = v, + hasA = (o) => #a in o, + getA = (o) => o.#a, + setA = (o, v) => o.#a = v, + hasM = (o) => #m in o, + callM = (o) => o.#m() + ); + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); +} + +{ + "instance private access in the body of a static private method"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, thisMethodLength, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method(_) { + staticThis = this; + thisMethodLength = this.#method.length; + hasX = (o) => #x in o; + getX = (o) => o.#x; + setX = (o, v) => o.#x = v; + hasA = (o) => #a in o; + getA = (o) => o.#a; + setA = (o, v) => o.#a = v; + hasM = (o) => #m in o; + callM = (o) => o.#m(); + }; + + static { + this.#method() + } + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); + expect(thisMethodLength).toBe(1); +} + +{ + "instance private access in the params of a static private method"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, thisMethodLength, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method(v = ( + staticThis = this, + thisMethodLength = this.#method.length, + hasX = (o) => #x in o, + getX = (o) => o.#x, + setX = (o, v) => o.#x = v, + hasA = (o) => #a in o, + getA = (o) => o.#a, + setA = (o, v) => o.#a = v, + hasM = (o) => #m in o, + callM = (o) => o.#m() + )) {}; + + static { + this.#method() + } + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); + expect(thisMethodLength).toBe(1); +} + +{ + "instance private access in everywhere mentioned above"; + let hasX, getX, setX, hasA, getA, setA, hasM, callM, staticThis, thisMethodLength, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x; + accessor #a; + #m() { return "#m" } + + x; + accessor a; + m() {} + + static #method({ + [(staticThis = this, thisMethodLength = this.#method.length, getX = (o) => o.#x)]: _ + } = ( + hasM = (o) => #m in o + )) { + hasA = (o) => #a in o; + } + + static { + hasX = (o) => #x in o; + getA = (o) => o.#a; + callM = (o) => o.#m(); + this.#method(); + } + + static #field = ( + setX = (o, v) => o.#x = v, + setA = (o, v) => o.#a = v + ); + } + + const foo = new OriginalFoo(); + const bar = new Foo(); + + expect(hasX(foo)).toBe(true); + expect(getX((setX(foo, "#x"), foo))).toBe("#x"); + expect(hasA(foo)).toBe(true); + expect(getA((setA(foo, "#a"), foo))).toBe("#a"); + expect(hasM(foo)).toBe(true); + expect(callM(foo)).toBe("#m"); + expect(hasX(bar)).toBe(false); + expect(hasA(bar)).toBe(false); + expect(hasM(bar)).toBe(false); + + expect(foo.hasOwnProperty("x")).toBe(true); + expect(bar.hasOwnProperty("x")).toBe(false); + + expect(OriginalFoo.prototype.hasOwnProperty("a")).toBe(true); + expect(Bar.prototype.hasOwnProperty("a")).toBe(false); + expect(OriginalFoo.prototype.hasOwnProperty("m")).toBe(true); + expect(Bar.prototype.hasOwnProperty("m")).toBe(false); + + expect(staticThis).toBe(Bar); + expect(thisMethodLength).toBe(1); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-access/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-access/input.js new file mode 100644 index 000000000000..dfaf6bfa2f49 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-access/input.js @@ -0,0 +1,20 @@ +const dec = () => {}; +let hasX, hasA, hasM; + +@dec +class Foo { + #x; + accessor #a; + #m() {} + + x; + accessor a; + m() {} + + static { + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + } +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-access/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-access/output.js new file mode 100644 index 000000000000..4e9014fc821a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-access/output.js @@ -0,0 +1,37 @@ +let _initClass, _staticBlock; +const dec = () => {}; +let hasX, hasA, hasM; +let _Foo; +new class extends babelHelpers.identity { + static [class Foo { + static { + [_Foo, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + _staticBlock = function () { + hasX = o => #x in o; + hasA = o => #a in o; + hasM = o => #m in o; + }; + } + #x; + #A; + get #a() { + return this.#A; + } + set #a(v) { + this.#A = v; + } + #m() {} + x; + #B; + get a() { + return this.#B; + } + set a(v) { + this.#B = v; + } + m() {} + }]; + constructor() { + super(_Foo), _staticBlock.call(this), _initClass(); + } +}(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/exec.js new file mode 100644 index 000000000000..f7c3bbc3f428 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/exec.js @@ -0,0 +1,33 @@ +{ + "instance private destructuring in a static block"; + let getX, getA, callM, staticThis, OriginalFoo; + + class Bar {} + + const dec = (Foo) => { + OriginalFoo = Foo; + return Bar; + }; + + @dec + class Foo { + #x = "#x"; + accessor #a = "#a"; + #m() { return "#m" } + + static { + staticThis = this; + getX = ({ #x: x }) => x; + getA = ({ #a: a }) => a; + callM = ({ #m: m }) => m(); + } + } + + const foo = new OriginalFoo(); + + expect(getX(foo)).toBe("#x"); + expect(getA(foo)).toBe("#a"); + expect(callM(foo)).toBe("#m"); + + expect(staticThis).toBe(Bar); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/input.js new file mode 100644 index 000000000000..1af597aab08d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/input.js @@ -0,0 +1,17 @@ +const dec = () => {}; +let getX, getA, callM; + +@dec +class Foo { + #x = "#x"; + accessor #a = "#a"; + #m() { return "#m" } + + static { + staticThis = this; + getX = ({ #x: x }) => x; + getA = ({ #a: a }) => a; + callM = ({ #m: m }) => m(); + } +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/options.json new file mode 100644 index 000000000000..25e614d30a7c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "proposal-destructuring-private", + ["proposal-decorators", { "version": "2023-11" }] + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/output.js new file mode 100644 index 000000000000..634dbf80aac5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-private-instance-element-destructuring/output.js @@ -0,0 +1,40 @@ +let _initClass, _staticBlock; +const dec = () => {}; +let getX, getA, callM; +let _Foo; +new class extends babelHelpers.identity { + static [class Foo { + static { + [_Foo, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + _staticBlock = function () { + staticThis = this; + getX = _p => { + var x = _p.#x; + return x; + }; + getA = _p2 => { + var a = _p2.#a; + return a; + }; + callM = _p3 => { + var m = _p3.#m; + return m(); + }; + }; + } + #x = "#x"; + #A = "#a"; + get #a() { + return this.#A; + } + set #a(v) { + this.#A = v; + } + #m() { + return "#m"; + } + }]; + constructor() { + super(_Foo), _staticBlock.call(this), _initClass(); + } +}(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-this/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-this/input.js new file mode 100644 index 000000000000..1b8d46cf3ac0 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-this/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +@dec +class Foo { + static { + this + } + static field = this; + static { + this + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-this/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-this/output.js new file mode 100644 index 000000000000..1d353756264c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-static-this/output.js @@ -0,0 +1,18 @@ +let _initClass; +const dec = () => {}; +let _Foo; +new class extends babelHelpers.identity { + static [class Foo { + static { + [_Foo, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + field = ((() => { + this; + })(), this); + constructor() { + super(_Foo), (() => { + this; + })(), _initClass(); + } +}(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-with-expr/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-with-expr/input.js new file mode 100644 index 000000000000..0cd5e45110b7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-with-expr/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +const Foo = @dec class Bar { + bar = new Bar(); +}; + +const foo = new Foo(); + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-with-expr/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-with-expr/output.js new file mode 100644 index 000000000000..61a8001e0ba2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement-with-expr/output.js @@ -0,0 +1,12 @@ +let _initClass, _Bar; +const dec = () => {}; +const Foo = (class Bar { + static { + [_Bar, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + bar = new _Bar(); + static { + _initClass(); + } +}, _Bar); +const foo = new Foo(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement/input.js new file mode 100644 index 000000000000..8f0a4dfe092f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +@dec +class Foo { + static foo = new Foo(); +} + +const foo = new Foo(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement/output.js new file mode 100644 index 000000000000..f52a3110135c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/replacement/output.js @@ -0,0 +1,15 @@ +let _initClass; +const dec = () => {}; +let _Foo; +new class extends babelHelpers.identity { + static [class Foo { + static { + [_Foo, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + }]; + foo = new _Foo(); + constructor() { + super(_Foo), _initClass(); + } +}(); +const foo = new _Foo(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-ast/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-ast/exec.js new file mode 100644 index 000000000000..49fad189f4e2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-ast/exec.js @@ -0,0 +1,33 @@ +var i = 0; + +function getKey() { + return (i++).toString(); +} + +let elements = []; + +function dec(fn, context) { + elements.push({ fn, context }); +} + +class Foo { + @dec + [getKey()]() { + return 1; + } + + @dec + [getKey()]() { + return 2; + } +} + +expect(elements).toHaveLength(2); + +expect(elements[0].context.name).toBe("0"); +expect(elements[0].fn()).toBe(1); + +expect(elements[1].context.name).toBe("1"); +expect(elements[1].fn()).toBe(2); + +expect(i).toBe(2); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-ast/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-ast/input.js new file mode 100644 index 000000000000..fd4743f81bc7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-ast/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +class Foo { + @dec + [getKey()]() { + return 1; + } + + @dec + [getKey()]() { + return 2; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-ast/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-ast/output.js new file mode 100644 index 000000000000..cef8fbb40e3c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-ast/output.js @@ -0,0 +1,18 @@ +var _Foo; +let _initProto, _computedKey, _computedKey2; +const dec = () => {}; +_computedKey = babelHelpers.toPropertyKey(getKey()); +_computedKey2 = babelHelpers.toPropertyKey(getKey()); +class Foo { + constructor() { + _initProto(this); + } + [_computedKey]() { + return 1; + } + [_computedKey2]() { + return 2; + } +} +_Foo = Foo; +[_initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 2, _computedKey], [dec, 2, _computedKey2]]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-value/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-value/exec.js new file mode 100644 index 000000000000..08cf5b80b55e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-value/exec.js @@ -0,0 +1,78 @@ +function getKey() { + return eval("0") +} + +let elements = []; + +function dec(fn, context) { + elements.push(fn); +} + +expect(() => { + class Foo { + @dec + [getKey()]() { + return 1; + } + + @dec + [getKey()]() { + return 2; + } + } +}).toThrow("Decorating two elements with the same name"); + +expect(() => { + class Foo { + @dec + [getKey()]() { + return 1; + } + + @dec + get [getKey()]() { + return 2; + } + } +}).toThrow("Decorating two elements with the same name"); + +expect(() => { + class Foo { + @dec + [getKey()]() { + return 1; + } + + @dec + set [getKey()](_) { + return 2; + } + } +}).toThrow("Decorating two elements with the same name"); + +expect(() => { + class Foo { + @dec + *[Symbol.iterator]() { + return 1; + } + + @dec + get [Symbol.iterator]() { + return function *() {}; + } + } +}).toThrow("Decorating two elements with the same name (get [Symbol.iterator]) is not supported yet"); + +expect(() => { + class Foo { + @dec + *[Symbol.iterator]() {} + + @dec + *[Symbol("Symbol.iterator")]() {} + + @dec + *"[Symbol.iterator]"() {} + } +}).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-value/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-value/input.js new file mode 100644 index 000000000000..0f6e2ca31d39 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-value/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +class Foo { + @dec + [getKeyI()]() { + return 1; + } + + @dec + [getKeyJ()]() { + return 2; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-value/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-value/output.js new file mode 100644 index 000000000000..7a78452862d2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/computed-keys-same-value/output.js @@ -0,0 +1,18 @@ +var _Foo; +let _initProto, _computedKey, _computedKey2; +const dec = () => {}; +_computedKey = babelHelpers.toPropertyKey(getKeyI()); +_computedKey2 = babelHelpers.toPropertyKey(getKeyJ()); +class Foo { + constructor() { + _initProto(this); + } + [_computedKey]() { + return 1; + } + [_computedKey2]() { + return 2; + } +} +_Foo = Foo; +[_initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 2, _computedKey], [dec, 2, _computedKey2]]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/method-and-field/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/method-and-field/exec.js new file mode 100644 index 000000000000..72e253d55578 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/method-and-field/exec.js @@ -0,0 +1,23 @@ +let elements = []; + +function dec(val, context) { + elements.push({ val, context }); +} + +class Foo { + @dec + a = 123; + + @dec + a() { + return 1; + } +} + +expect(elements).toHaveLength(2); + +expect(elements[0].context.name).toBe("a"); +expect(elements[0].val()).toBe(1); + +expect(elements[1].context.name).toBe("a"); +expect(elements[1].val).toBe(undefined); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/method-and-field/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/method-and-field/input.js new file mode 100644 index 000000000000..e2bfd2a7b415 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/method-and-field/input.js @@ -0,0 +1,10 @@ +const dec = () => {}; +class Foo { + @dec + a = 123; + + @dec + a() { + return 1; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/method-and-field/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/method-and-field/output.js new file mode 100644 index 000000000000..e5378072cd60 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/method-and-field/output.js @@ -0,0 +1,14 @@ +var _Foo; +let _initProto, _init_a, _init_extra_a; +const dec = () => {}; +class Foo { + constructor() { + babelHelpers.defineProperty(this, "a", (_initProto(this), _init_a(this, 123))); + _init_extra_a(this); + } + a() { + return 1; + } +} +_Foo = Foo; +[_init_a, _init_extra_a, _initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 0, "a"], [dec, 2, "a"]]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/methods-with-same-key/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/methods-with-same-key/exec.js new file mode 100644 index 000000000000..3cddfd510c50 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/methods-with-same-key/exec.js @@ -0,0 +1,20 @@ +let elements = []; + +function dec(val, context) { + elements.push(val); +} + +expect(() => { + class Foo { + @dec + a() { + return 1; + } + + @dec + a() { + return 2; + } + } +}).toThrow("Decorating two elements with the same name"); + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/methods-with-same-key/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/methods-with-same-key/input.js new file mode 100644 index 000000000000..ab961fbc9dfb --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/methods-with-same-key/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +class Foo { + @dec + a() { + return 1; + } + + @dec + a() { + return 2; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/methods-with-same-key/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/methods-with-same-key/output.js new file mode 100644 index 000000000000..33a7d6e6451f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/methods-with-same-key/output.js @@ -0,0 +1,16 @@ +var _Foo; +let _initProto; +const dec = () => {}; +class Foo { + constructor() { + _initProto(this); + } + a() { + return 1; + } + a() { + return 2; + } +} +_Foo = Foo; +[_initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 2, "a"], [dec, 2, "a"]]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-ast/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-ast/input.js new file mode 100644 index 000000000000..fd4743f81bc7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-ast/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +class Foo { + @dec + [getKey()]() { + return 1; + } + + @dec + [getKey()]() { + return 2; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-ast/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-ast/output.js new file mode 100644 index 000000000000..dd3623415e03 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-ast/output.js @@ -0,0 +1,16 @@ +let _initProto, _computedKey, _computedKey2; +const dec = () => {}; +class Foo { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 2, _computedKey], [dec, 2, _computedKey2]]).e; + } + constructor() { + _initProto(this); + } + [_computedKey = babelHelpers.toPropertyKey(getKey())]() { + return 1; + } + [_computedKey2 = babelHelpers.toPropertyKey(getKey())]() { + return 2; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-value/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-value/input.js new file mode 100644 index 000000000000..0f6e2ca31d39 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-value/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +class Foo { + @dec + [getKeyI()]() { + return 1; + } + + @dec + [getKeyJ()]() { + return 2; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-value/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-value/output.js new file mode 100644 index 000000000000..86436e2177d7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/computed-keys-same-value/output.js @@ -0,0 +1,16 @@ +let _initProto, _computedKey, _computedKey2; +const dec = () => {}; +class Foo { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 2, _computedKey], [dec, 2, _computedKey2]]).e; + } + constructor() { + _initProto(this); + } + [_computedKey = babelHelpers.toPropertyKey(getKeyI())]() { + return 1; + } + [_computedKey2 = babelHelpers.toPropertyKey(getKeyJ())]() { + return 2; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/method-and-field/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/method-and-field/input.js new file mode 100644 index 000000000000..e2bfd2a7b415 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/method-and-field/input.js @@ -0,0 +1,10 @@ +const dec = () => {}; +class Foo { + @dec + a = 123; + + @dec + a() { + return 1; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/method-and-field/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/method-and-field/output.js new file mode 100644 index 000000000000..c2132f772058 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/method-and-field/output.js @@ -0,0 +1,14 @@ +let _initProto, _init_a, _init_extra_a; +const dec = () => {}; +class Foo { + static { + [_init_a, _init_extra_a, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 0, "a"], [dec, 2, "a"]]).e; + } + constructor() { + _init_extra_a(this); + } + a = (_initProto(this), _init_a(this, 123)); + a() { + return 1; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/methods-with-same-key/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/methods-with-same-key/input.js new file mode 100644 index 000000000000..ab961fbc9dfb --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/methods-with-same-key/input.js @@ -0,0 +1,12 @@ +const dec = () => {}; +class Foo { + @dec + a() { + return 1; + } + + @dec + a() { + return 2; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/methods-with-same-key/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/methods-with-same-key/output.js new file mode 100644 index 000000000000..8f23669da725 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/methods-with-same-key/output.js @@ -0,0 +1,16 @@ +let _initProto; +const dec = () => {}; +class Foo { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "a"], [dec, 2, "a"]]).e; + } + constructor() { + _initProto(this); + } + a() { + return 1; + } + a() { + return 2; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/options.json new file mode 100644 index 000000000000..4c274676d3c2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-duplicated-keys/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-anonymous/input.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-anonymous/input.mjs new file mode 100644 index 000000000000..05db70faed30 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-anonymous/input.mjs @@ -0,0 +1 @@ +export default @dec class A {} \ No newline at end of file diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-anonymous/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-anonymous/output.mjs new file mode 100644 index 000000000000..46490b169585 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-anonymous/output.mjs @@ -0,0 +1,11 @@ +let _initClass; +let _A; +class A { + static { + [_A, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static { + _initClass(); + } +} +export { _A as default }; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-named/input.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-named/input.mjs new file mode 100644 index 000000000000..31cdac17444e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-named/input.mjs @@ -0,0 +1 @@ +export default @dec class {} \ No newline at end of file diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-named/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-named/output.mjs new file mode 100644 index 000000000000..fe6e85aaa766 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/default-named/output.mjs @@ -0,0 +1,11 @@ +let _initClass; +let _default2; +class _default { + static { + [_default2, _initClass] = babelHelpers.applyDecs2311(babelHelpers.setFunctionName(this, "default"), [dec], []).c; + } + static { + _initClass(); + } +} +export { _default2 as default }; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/member-decorator/input.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/member-decorator/input.mjs new file mode 100644 index 000000000000..f72e0e9c2249 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/member-decorator/input.mjs @@ -0,0 +1,3 @@ +export class A { + @dec x; +} \ No newline at end of file diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/member-decorator/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/member-decorator/output.mjs new file mode 100644 index 000000000000..905d663392f8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/member-decorator/output.mjs @@ -0,0 +1,10 @@ +let _init_x, _init_extra_x; +export class A { + static { + [_init_x, _init_extra_x] = babelHelpers.applyDecs2311(this, [], [[dec, 0, "x"]]).e; + } + constructor() { + _init_extra_x(this); + } + x = _init_x(this); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/named/input.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/named/input.mjs new file mode 100644 index 000000000000..367f946714b0 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/named/input.mjs @@ -0,0 +1 @@ +export @dec class A {} \ No newline at end of file diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/named/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/named/output.mjs new file mode 100644 index 000000000000..584f86d82924 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/named/output.mjs @@ -0,0 +1,11 @@ +let _initClass; +let _A; +class A { + static { + [_A, _initClass] = babelHelpers.applyDecs2311(this, [dec], []).c; + } + static { + _initClass(); + } +} +export { _A as A }; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/no-decorators/input.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/no-decorators/input.mjs new file mode 100644 index 000000000000..bc88730f95a8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/no-decorators/input.mjs @@ -0,0 +1,4 @@ +export class A {} + +class B {} +export { B }; \ No newline at end of file diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/no-decorators/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/no-decorators/output.mjs new file mode 100644 index 000000000000..9ac373c42b10 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/no-decorators/output.mjs @@ -0,0 +1,3 @@ +export class A {} +class B {} +export { B }; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/options.json new file mode 100644 index 000000000000..4c274676d3c2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-exported/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/exec.js new file mode 100644 index 000000000000..3b37fbff18a7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static a; + @dec static #a; + + @dec static "b" + @dec static ["c"]; + + @dec static 0; + @dec static [1]; + + @dec static 2n; + @dec static [3n]; + + @dec static [f()]; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/input.js new file mode 100644 index 000000000000..3b37fbff18a7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static a; + @dec static #a; + + @dec static "b" + @dec static ["c"]; + + @dec static 0; + @dec static [1]; + + @dec static 2n; + @dec static [3n]; + + @dec static [f()]; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/options.json new file mode 100644 index 000000000000..e6953fa50f0b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "14.6.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/output.js new file mode 100644 index 000000000000..77fba93f071e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/context-name/output.js @@ -0,0 +1,29 @@ +var _Foo; +let _init_a, _init_extra_a, _init_a2, _init_extra_a2, _init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2, _init_computedKey3, _init_extra_computedKey3, _init_computedKey4, _init_extra_computedKey4, _init_computedKey5, _init_extra_computedKey5, _init_computedKey6, _init_extra_computedKey6, _computedKey, _init_computedKey7, _init_extra_computedKey7; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +_computedKey = babelHelpers.toPropertyKey(f()); +class Foo {} +_Foo = Foo; +[_init_a, _init_extra_a, _init_a2, _init_extra_a2, _init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2, _init_computedKey3, _init_extra_computedKey3, _init_computedKey4, _init_extra_computedKey4, _init_computedKey5, _init_extra_computedKey5, _init_computedKey6, _init_extra_computedKey6, _init_computedKey7, _init_extra_computedKey7] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 8, "a"], [dec, 8, "a", o => babelHelpers.assertClassBrand(_Foo, o, _a)._, (o, v) => _a._ = babelHelpers.assertClassBrand(_Foo, o, v)], [dec, 8, "b"], [dec, 8, "c"], [dec, 8, 0], [dec, 8, 1], [dec, 8, 2n], [dec, 8, 3n], [dec, 8, _computedKey]]).e; +babelHelpers.defineProperty(Foo, "a", _init_a()); +var _a = { + _: (_init_extra_a(), _init_a2()) +}; +babelHelpers.defineProperty(Foo, "b", (_init_extra_a2(), _init_computedKey())); +babelHelpers.defineProperty(Foo, "c", (_init_extra_computedKey(), _init_computedKey2())); +babelHelpers.defineProperty(Foo, 0, (_init_extra_computedKey2(), _init_computedKey3())); +babelHelpers.defineProperty(Foo, 1, (_init_extra_computedKey3(), _init_computedKey4())); +babelHelpers.defineProperty(Foo, 2n, (_init_extra_computedKey4(), _init_computedKey5())); +babelHelpers.defineProperty(Foo, 3n, (_init_extra_computedKey5(), _init_computedKey6())); +babelHelpers.defineProperty(Foo, _computedKey, (_init_extra_computedKey6(), _init_computedKey7())); +_init_extra_computedKey7(); +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/private/exec.js new file mode 100644 index 000000000000..3662412777c6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/private/exec.js @@ -0,0 +1,44 @@ +function dec(_v, context) { + return function (v) { + this[context.name + 'Context'] = context; + return (v || 1) + 1; + } +} + +class Foo { + @dec + #a; + + @dec + #b = 123; +} + +let foo = new Foo(); + +const aContext = foo['#aContext']; +const bContext = foo['#bContext']; + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(false); + +expect(aContext.access.get(foo)).toBe(2); +expect(() => aContext.access.get({})).toThrow(TypeError); +aContext.access.set(foo, 123); +expect(aContext.access.get(foo)).toBe(123); +expect(() => aContext.access.set({}, 456)).toThrow(TypeError); +expect(aContext.access.get(foo)).toBe(123); +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('field'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.access.get(foo)).toBe(124); +bContext.access.set(foo, 123); +expect(bContext.access.get(foo)).toBe(123); +expect(bContext.name).toBe('#b'); +expect(bContext.kind).toBe('field'); +expect(bContext.static).toBe(false); +expect(bContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/private/input.js new file mode 100644 index 000000000000..2cd77e99b7e3 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/private/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec + #a; + + @dec + #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/private/output.js new file mode 100644 index 000000000000..47c00d1fea2b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/private/output.js @@ -0,0 +1,14 @@ +var _Foo; +let _init_a, _init_extra_a, _init_b, _init_extra_b; +const dec = () => {}; +var _a = /*#__PURE__*/new WeakMap(); +var _b = /*#__PURE__*/new WeakMap(); +class Foo { + constructor() { + babelHelpers.classPrivateFieldInitSpec(this, _a, _init_a(this)); + babelHelpers.classPrivateFieldInitSpec(this, _b, (_init_extra_a(this), _init_b(this, 123))); + _init_extra_b(this); + } +} +_Foo = Foo; +[_init_a, _init_extra_a, _init_b, _init_extra_b] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 0, "a", o => babelHelpers.classPrivateFieldGet2(_a, o), (o, v) => babelHelpers.classPrivateFieldSet2(_a, o, v)], [dec, 0, "b", o => babelHelpers.classPrivateFieldGet2(_b, o), (o, v) => babelHelpers.classPrivateFieldSet2(_b, o, v)]], 0, _ => _b.has(babelHelpers.checkInRHS(_))).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/public/exec.js new file mode 100644 index 000000000000..e9065e5b7b07 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/public/exec.js @@ -0,0 +1,67 @@ +function dec(_v, context) { + return function (v) { + this[context.name + 'Context'] = context; + return (v || 1) + 1; + } +} + +class Foo { + @dec + a; + + @dec + b = 123; + + @dec + ['c'] = 456; +} + +let foo = new Foo(); + +const aContext = foo['aContext']; +const bContext = foo['bContext']; +const cContext = foo['cContext']; + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(foo.a).toBe(2); +expect(aContext.access.get(foo)).toBe(2); +foo.a = 123; +expect(foo.a).toBe(123); +expect(aContext.access.get(foo)).toBe(123); +aContext.access.set(foo, 456); +expect(foo.a).toBe(456); +expect(aContext.access.get(foo)).toBe(456); +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('field'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); +expect(foo.hasOwnProperty('a')).toBe(true); +expect(Foo.prototype.hasOwnProperty('a')).toBe(false); + +expect(foo.b).toBe(124); +foo.b = 123; +expect(foo.b).toBe(123); +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('field'); +expect(bContext.static).toBe(false); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); +expect(foo.hasOwnProperty('b')).toBe(true); +expect(Foo.prototype.hasOwnProperty('b')).toBe(false); + +expect(foo.c).toBe(457); +foo.c = 456; +expect(foo.c).toBe(456); +expect(cContext.name).toBe('c'); +expect(cContext.kind).toBe('field'); +expect(cContext.static).toBe(false); +expect(cContext.private).toBe(false); +expect(typeof cContext.addInitializer).toBe('function'); +expect(foo.hasOwnProperty('c')).toBe(true); +expect(Foo.prototype.hasOwnProperty('c')).toBe(false); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/public/input.js new file mode 100644 index 000000000000..16a36d324047 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/public/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class Foo { + @dec + a; + + @dec + b = 123; + + @dec + ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/public/output.js new file mode 100644 index 000000000000..c2195bfc8c96 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/public/output.js @@ -0,0 +1,13 @@ +var _Foo; +let _init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey; +const dec = () => {}; +class Foo { + constructor() { + babelHelpers.defineProperty(this, "a", _init_a(this)); + babelHelpers.defineProperty(this, "b", (_init_extra_a(this), _init_b(this, 123))); + babelHelpers.defineProperty(this, 'c', (_init_extra_b(this), _init_computedKey(this, 456))); + _init_extra_computedKey(this); + } +} +_Foo = Foo; +[_init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 0, "a"], [dec, 0, "b"], [dec, 0, 'c']]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-private/exec.js new file mode 100644 index 000000000000..7c6212733b7a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-private/exec.js @@ -0,0 +1,42 @@ +function dec(_v, context) { + return function (v) { + this[context.name + 'Context'] = context; + return (v || 1) + 1; + } +} + +class Foo { + @dec + static #a; + + @dec + static #b = 123; +} + +const aContext = Foo['#aContext']; +const bContext = Foo['#bContext']; + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(false); + +expect(aContext.access.get(Foo)).toBe(2); +expect(() => aContext.access.get({})).toThrow(TypeError); +aContext.access.set(Foo, 123); +expect(aContext.access.get(Foo)).toBe(123); +expect(() => aContext.access.set({}, 456)).toThrow(TypeError); +expect(aContext.access.get(Foo)).toBe(123); +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('field'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.access.get(Foo)).toBe(124); +bContext.access.set(Foo, 123); +expect(bContext.access.get(Foo)).toBe(123); +expect(bContext.name).toBe('#b'); +expect(bContext.kind).toBe('field'); +expect(bContext.static).toBe(true); +expect(bContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-private/input.js new file mode 100644 index 000000000000..bc6f56f17527 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-private/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec + static #a; + + @dec + static #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-private/output.js new file mode 100644 index 000000000000..cfd5e536fdab --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-private/output.js @@ -0,0 +1,13 @@ +var _Foo; +let _init_a, _init_extra_a, _init_b, _init_extra_b; +const dec = () => {}; +class Foo {} +_Foo = Foo; +[_init_a, _init_extra_a, _init_b, _init_extra_b] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 8, "a", o => babelHelpers.assertClassBrand(_Foo, o, _a)._, (o, v) => _a._ = babelHelpers.assertClassBrand(_Foo, o, v)], [dec, 8, "b", o => babelHelpers.assertClassBrand(_Foo, o, _b)._, (o, v) => _b._ = babelHelpers.assertClassBrand(_Foo, o, v)]]).e; +var _a = { + _: _init_a() +}; +var _b = { + _: (_init_extra_a(), _init_b(123)) +}; +_init_extra_b(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-public/exec.js new file mode 100644 index 000000000000..8873aaa04353 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-public/exec.js @@ -0,0 +1,62 @@ +function dec(_v, context) { + return function (v) { + this[context.name + 'Context'] = context; + return (v || 1) + 1; + } +} + +class Foo { + @dec + static a; + + @dec + static b = 123; + + @dec + static ['c'] = 456; +} + +const aContext = Foo['aContext']; +const bContext = Foo['bContext']; +const cContext = Foo['cContext']; + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(Foo.a).toBe(2); +expect(aContext.access.get(Foo)).toBe(2); +Foo.a = 123; +expect(Foo.a).toBe(123); +expect(aContext.access.get(Foo)).toBe(123); +aContext.access.set(Foo, 456); +expect(Foo.a).toBe(456); +expect(aContext.access.get(Foo)).toBe(456); +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('field'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); +expect(Foo.hasOwnProperty('a')).toBe(true); + +expect(Foo.b).toBe(124); +Foo.b = 123; +expect(Foo.b).toBe(123); +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('field'); +expect(bContext.static).toBe(true); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); +expect(Foo.hasOwnProperty('b')).toBe(true); + +expect(Foo.c).toBe(457); +Foo.c = 456; +expect(Foo.c).toBe(456); +expect(cContext.name).toBe('c'); +expect(cContext.kind).toBe('field'); +expect(cContext.static).toBe(true); +expect(cContext.private).toBe(false); +expect(typeof cContext.addInitializer).toBe('function'); +expect(Foo.hasOwnProperty('c')).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-public/input.js new file mode 100644 index 000000000000..e7e44bf1ec16 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-public/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class Foo { + @dec + static a; + + @dec + static b = 123; + + @dec + static ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-public/output.js new file mode 100644 index 000000000000..2eb3f8837b3f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields--to-es2015/static-public/output.js @@ -0,0 +1,10 @@ +var _Foo; +let _init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey; +const dec = () => {}; +class Foo {} +_Foo = Foo; +[_init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 8, "a"], [dec, 8, "b"], [dec, 8, 'c']]).e; +babelHelpers.defineProperty(Foo, "a", _init_a()); +babelHelpers.defineProperty(Foo, "b", (_init_extra_a(), _init_b(123))); +babelHelpers.defineProperty(Foo, 'c', (_init_extra_b(), _init_computedKey(456))); +_init_extra_computedKey(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/exec.js new file mode 100644 index 000000000000..3b37fbff18a7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static a; + @dec static #a; + + @dec static "b" + @dec static ["c"]; + + @dec static 0; + @dec static [1]; + + @dec static 2n; + @dec static [3n]; + + @dec static [f()]; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/input.js new file mode 100644 index 000000000000..3b37fbff18a7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static a; + @dec static #a; + + @dec static "b" + @dec static ["c"]; + + @dec static 0; + @dec static [1]; + + @dec static 2n; + @dec static [3n]; + + @dec static [f()]; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/output.js new file mode 100644 index 000000000000..d00e6ed4f697 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/context-name/output.js @@ -0,0 +1,29 @@ +let _init_a, _init_extra_a, _init_a2, _init_extra_a2, _init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2, _init_computedKey3, _init_extra_computedKey3, _init_computedKey4, _init_extra_computedKey4, _init_computedKey5, _init_extra_computedKey5, _init_computedKey6, _init_extra_computedKey6, _computedKey, _init_computedKey7, _init_extra_computedKey7; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +class Foo { + static { + [_init_a, _init_extra_a, _init_a2, _init_extra_a2, _init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2, _init_computedKey3, _init_extra_computedKey3, _init_computedKey4, _init_extra_computedKey4, _init_computedKey5, _init_extra_computedKey5, _init_computedKey6, _init_extra_computedKey6, _init_computedKey7, _init_extra_computedKey7] = babelHelpers.applyDecs2311(this, [], [[dec, 8, "a"], [dec, 8, "a", o => o.#a, (o, v) => o.#a = v], [dec, 8, "b"], [dec, 8, "c"], [dec, 8, 0], [dec, 8, 1], [dec, 8, 2n], [dec, 8, 3n], [dec, 8, _computedKey]]).e; + } + static a = _init_a(); + static #a = (_init_extra_a(), _init_a2()); + static "b" = (_init_extra_a2(), _init_computedKey()); + static ["c"] = (_init_extra_computedKey(), _init_computedKey2()); + static 0 = (_init_extra_computedKey2(), _init_computedKey3()); + static [1] = (_init_extra_computedKey3(), _init_computedKey4()); + static 2n = (_init_extra_computedKey4(), _init_computedKey5()); + static [3n] = (_init_extra_computedKey5(), _init_computedKey6()); + static [_computedKey = babelHelpers.toPropertyKey(f())] = (_init_extra_computedKey6(), _init_computedKey7()); + static { + _init_extra_computedKey7(); + } +} +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/options.json new file mode 100644 index 000000000000..4c274676d3c2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/private/input.js new file mode 100644 index 000000000000..2cd77e99b7e3 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/private/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec + #a; + + @dec + #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/private/output.js new file mode 100644 index 000000000000..49da84e0d0f0 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/private/output.js @@ -0,0 +1,12 @@ +let _init_a, _init_extra_a, _init_b, _init_extra_b; +const dec = () => {}; +class Foo { + static { + [_init_a, _init_extra_a, _init_b, _init_extra_b] = babelHelpers.applyDecs2311(this, [], [[dec, 0, "a", o => o.#a, (o, v) => o.#a = v], [dec, 0, "b", o => o.#b, (o, v) => o.#b = v]], 0, _ => #b in _).e; + } + constructor() { + _init_extra_b(this); + } + #a = _init_a(this); + #b = (_init_extra_a(this), _init_b(this, 123)); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/public/input.js new file mode 100644 index 000000000000..16a36d324047 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/public/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class Foo { + @dec + a; + + @dec + b = 123; + + @dec + ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/public/output.js new file mode 100644 index 000000000000..add3ee68ae2d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/public/output.js @@ -0,0 +1,13 @@ +let _init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey; +const dec = () => {}; +class Foo { + static { + [_init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(this, [], [[dec, 0, "a"], [dec, 0, "b"], [dec, 0, 'c']]).e; + } + constructor() { + _init_extra_computedKey(this); + } + a = _init_a(this); + b = (_init_extra_a(this), _init_b(this, 123)); + ['c'] = (_init_extra_b(this), _init_computedKey(this, 456)); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-private/input.js new file mode 100644 index 000000000000..bc6f56f17527 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-private/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec + static #a; + + @dec + static #b = 123; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-private/output.js new file mode 100644 index 000000000000..3becba71aae7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-private/output.js @@ -0,0 +1,12 @@ +let _init_a, _init_extra_a, _init_b, _init_extra_b; +const dec = () => {}; +class Foo { + static { + [_init_a, _init_extra_a, _init_b, _init_extra_b] = babelHelpers.applyDecs2311(this, [], [[dec, 8, "a", o => o.#a, (o, v) => o.#a = v], [dec, 8, "b", o => o.#b, (o, v) => o.#b = v]]).e; + } + static #a = _init_a(); + static #b = (_init_extra_a(), _init_b(123)); + static { + _init_extra_b(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-public/input.js new file mode 100644 index 000000000000..e7e44bf1ec16 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-public/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class Foo { + @dec + static a; + + @dec + static b = 123; + + @dec + static ['c'] = 456; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-public/output.js new file mode 100644 index 000000000000..82e2269e359e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-fields/static-public/output.js @@ -0,0 +1,13 @@ +let _init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey; +const dec = () => {}; +class Foo { + static { + [_init_a, _init_extra_a, _init_b, _init_extra_b, _init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(this, [], [[dec, 8, "a"], [dec, 8, "b"], [dec, 8, 'c']]).e; + } + static a = _init_a(); + static b = (_init_extra_a(), _init_b(123)); + static ['c'] = (_init_extra_b(), _init_computedKey(456)); + static { + _init_extra_computedKey(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/exec.js new file mode 100644 index 000000000000..5e7003b637d8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static get a() {}; + @dec static get #a() {}; + + @dec static get "b"() {} + @dec static get ["c"]() {}; + + @dec static get 0() {}; + @dec static get [1]() {}; + + @dec static get 2n() {}; + @dec static get [3n]() {}; + + @dec static get [f()]() {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/input.js new file mode 100644 index 000000000000..5e7003b637d8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static get a() {}; + @dec static get #a() {}; + + @dec static get "b"() {} + @dec static get ["c"]() {}; + + @dec static get 0() {}; + @dec static get [1]() {}; + + @dec static get 2n() {}; + @dec static get [3n]() {}; + + @dec static get [f()]() {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/options.json new file mode 100644 index 000000000000..e6953fa50f0b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "14.6.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/output.js new file mode 100644 index 000000000000..ae98bcd9a0d0 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/context-name/output.js @@ -0,0 +1,29 @@ +var _Foo; +let _initStatic, _call_a, _computedKey; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +_computedKey = babelHelpers.toPropertyKey(f()); +class Foo { + static get a() {} + static get "b"() {} + static get ["c"]() {} + static get 0() {} + static get [1]() {} + static get 2n() {} + static get [3n]() {} + static get [_computedKey]() {} +} +_Foo = Foo; +(() => { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 11, "a"], [dec, 11, "a", function () {}], [dec, 11, "b"], [dec, 11, "c"], [dec, 11, 0], [dec, 11, 1], [dec, 11, 2n], [dec, 11, 3n], [dec, 11, _computedKey]]).e; + _initStatic(_Foo); +})(); +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/private/exec.js new file mode 100644 index 000000000000..0936aba0b50e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/private/exec.js @@ -0,0 +1,45 @@ +function dec(get, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(get.name).toEqual("get " + context.name); + return function () { + return get.call(this) + 1; + } +} + +class Foo { + value = 1; + + @dec + get #a() { + return this.value; + } + + getA() { + return this.#a; + } +} + +let foo = new Foo(); + +const aContext = foo['#aContext']; + +expect(aContext.access).not.toHaveProperty("set"); + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(false); + +expect(aContext.access.get(foo)).toBe(2); +expect(() => aContext.access.get({})).toThrow(TypeError); +expect(foo.getA()).toBe(2); +foo.value = 123; +expect(aContext.access.get(foo)).toBe(124); +expect(foo.getA()).toBe(124); +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('getter'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/private/input.js new file mode 100644 index 000000000000..28519502bf46 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + get #a() { + return this.value; + } + + getA() { + return this.#a; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/private/output.js new file mode 100644 index 000000000000..55a657045d5c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/private/output.js @@ -0,0 +1,17 @@ +var _Foo; +let _initProto, _call_a; +const dec = () => {}; +var _Foo_brand = /*#__PURE__*/new WeakSet(); +class Foo { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Foo_brand); + babelHelpers.defineProperty(this, "value", (_initProto(this), 1)); + } + getA() { + return babelHelpers.classPrivateGetter(_Foo_brand, this, _call_a); + } +} +_Foo = Foo; +[_call_a, _initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 3, "a", function () { + return this.value; +}]], 0, _ => _Foo_brand.has(babelHelpers.checkInRHS(_))).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/public/exec.js new file mode 100644 index 000000000000..c4592966d8df --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/public/exec.js @@ -0,0 +1,60 @@ +function dec(get, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(get.name).toEqual("get " + context.name); + return function () { + return get.call(this) + 1; + } +} + +class Foo { + value = 1; + + @dec + get a() { + return this.value; + } + + @dec + get ['b']() { + return this.value; + } +} + +let foo = new Foo(); + +const aContext = foo['aContext']; +const bContext = foo['bContext']; + +expect(aContext.access).not.toHaveProperty("set"); +expect(bContext.access).not.toHaveProperty("set"); + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(foo.a).toBe(2); +expect(foo.b).toBe(2); +expect(aContext.access.get(foo)).toBe(2); +expect(bContext.access.get(foo)).toBe(2); +foo.value = 123; +expect(foo.a).toBe(124); +expect(foo.b).toBe(124); +expect(aContext.access.get(foo)).toBe(124); +expect(bContext.access.get(foo)).toBe(124); + +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('getter'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('getter'); +expect(bContext.static).toBe(false); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/public/input.js new file mode 100644 index 000000000000..392f9e03412f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + get a() { + return this.value; + } + + @dec + get ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/public/output.js new file mode 100644 index 000000000000..2c5891111e8a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/public/output.js @@ -0,0 +1,16 @@ +var _Foo; +let _initProto; +const dec = () => {}; +class Foo { + constructor() { + babelHelpers.defineProperty(this, "value", (_initProto(this), 1)); + } + get a() { + return this.value; + } + get ['b']() { + return this.value; + } +} +_Foo = Foo; +[_initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 3, "a"], [dec, 3, 'b']]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-private/exec.js new file mode 100644 index 000000000000..1e25bdfad497 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-private/exec.js @@ -0,0 +1,44 @@ +function dec(get, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(get.name).toEqual("get " + context.name); + return function () { + return get.call(this) + 1; + } +} + +class Foo { + static value = 1; + + @dec + static get #a() { + return this.value; + } + + static getA() { + return this.#a; + } +} + +const aContext = Foo['#aContext']; + +expect(aContext.access).not.toHaveProperty("set"); + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(false); + +expect(aContext.access.get(Foo)).toBe(2); +expect(() => aContext.access.get({})).toThrow(TypeError); +expect(Foo.getA()).toBe(2); +Foo.value = 123; +expect(aContext.access.get(Foo)).toBe(124); +expect(Foo.getA()).toBe(124); + +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('getter'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-private/input.js new file mode 100644 index 000000000000..9d64c02982da --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static get #a() { + return this.value; + } + + static getA() { + return this.#a; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-private/output.js new file mode 100644 index 000000000000..581ecdf11d6a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-private/output.js @@ -0,0 +1,16 @@ +var _Foo; +let _initStatic, _call_a; +const dec = () => {}; +class Foo { + static getA() { + return babelHelpers.classPrivateGetter(Foo, this, _call_a); + } +} +_Foo = Foo; +(() => { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 11, "a", function () { + return this.value; + }]]).e; + _initStatic(_Foo); +})(); +babelHelpers.defineProperty(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-public/exec.js new file mode 100644 index 000000000000..f7c9745ecbae --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-public/exec.js @@ -0,0 +1,58 @@ +function dec(get, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(get.name).toEqual("get " + context.name); + return function () { + return get.call(this) + 1; + } +} + +class Foo { + static value = 1; + + @dec + static get a() { + return this.value; + } + + @dec + static get ['b']() { + return this.value; + } +} + +const aContext = Foo['aContext']; +const bContext = Foo['bContext']; + +expect(aContext.access).not.toHaveProperty("set"); +expect(bContext.access).not.toHaveProperty("set"); + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(Foo.a).toBe(2); +expect(Foo.b).toBe(2); +expect(aContext.access.get(Foo)).toBe(2); +expect(bContext.access.get(Foo)).toBe(2); +Foo.value = 123; +expect(Foo.a).toBe(124); +expect(Foo.b).toBe(124); +expect(aContext.access.get(Foo)).toBe(124); +expect(bContext.access.get(Foo)).toBe(124); + +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('getter'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('getter'); +expect(bContext.static).toBe(true); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-public/input.js new file mode 100644 index 000000000000..3bc53fb17cc5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static get a() { + return this.value; + } + + @dec + static get ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-public/output.js new file mode 100644 index 000000000000..dbe7f03b8434 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters--to-es2015/static-public/output.js @@ -0,0 +1,17 @@ +var _Foo; +let _initStatic; +const dec = () => {}; +class Foo { + static get a() { + return this.value; + } + static get ['b']() { + return this.value; + } +} +_Foo = Foo; +(() => { + [_initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 11, "a"], [dec, 11, 'b']]).e; + _initStatic(_Foo); +})(); +babelHelpers.defineProperty(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/private/exec.js new file mode 100644 index 000000000000..4fd73c4c5ca1 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/private/exec.js @@ -0,0 +1,74 @@ +function dec(value, context) { + context.addInitializer(function() { + this[context.name + '_' + context.kind + 'Context'] = context; + }); + + if (context.kind === 'getter') { + return function () { + return value.call(this) + 1; + } + } else { + return function (v) { + return value.call(this, v + 1); + } + } +} + +class Foo { + value = 1; + + @dec + get #a() { + return this.value; + } + + @dec + set #a(v) { + this.value = v; + } + + getA() { + return this.#a; + } + + setA(v) { + this.#a = v; + } +} + +let foo = new Foo(); + +const a_getterContext = foo['#a_getterContext']; +const a_setterContext = foo['#a_setterContext']; + +expect(a_getterContext.access.has(foo)).toBe(true); +expect(a_getterContext.access.has({})).toBe(false); +expect(a_getterContext.access.has(Object.create(foo))).toBe(false); +expect(a_setterContext.access.has(foo)).toBe(true); +expect(a_setterContext.access.has({})).toBe(false); +expect(a_setterContext.access.has(Object.create(foo))).toBe(false); +expect(a_getterContext.access.has).not.toBe(a_setterContext.access.has); + +expect(a_getterContext.access.get(foo)).toBe(2); +expect(() => a_getterContext.access.get({})).toThrow(TypeError); +expect(foo.getA()).toBe(2); +a_setterContext.access.set(foo, 123); +expect(a_getterContext.access.get(foo)).toBe(125); +expect(() => a_setterContext.access.set({}, 456)).toThrow(TypeError); +expect(a_getterContext.access.get(foo)).toBe(125); +expect(foo.getA()).toBe(125); +foo.setA(456); +expect(a_getterContext.access.get(foo)).toBe(458); +expect(foo.getA()).toBe(458); + +expect(a_getterContext.name).toBe('#a'); +expect(a_getterContext.kind).toBe('getter'); +expect(a_getterContext.static).toBe(false); +expect(a_getterContext.private).toBe(true); +expect(typeof a_getterContext.addInitializer).toBe('function'); + +expect(a_setterContext.name).toBe('#a'); +expect(a_setterContext.kind).toBe('setter'); +expect(a_setterContext.static).toBe(false); +expect(a_setterContext.private).toBe(true); +expect(typeof a_setterContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/private/input.js new file mode 100644 index 000000000000..fdf137cc4a64 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/private/input.js @@ -0,0 +1,22 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + get #a() { + return this.value; + } + + @dec + set #a(v) { + this.value = v; + } + + getA() { + return this.#a; + } + + setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/private/output.js new file mode 100644 index 000000000000..7ec33495ada2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/private/output.js @@ -0,0 +1,22 @@ +var _Foo; +let _initProto, _call_a, _call_a2; +const dec = () => {}; +var _Foo_brand = /*#__PURE__*/new WeakSet(); +class Foo { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Foo_brand); + babelHelpers.defineProperty(this, "value", (_initProto(this), 1)); + } + getA() { + return babelHelpers.classPrivateGetter(_Foo_brand, this, _call_a); + } + setA(v) { + babelHelpers.classPrivateSetter(_Foo_brand, _call_a2, this, v); + } +} +_Foo = Foo; +[_call_a, _call_a2, _initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 3, "a", function () { + return this.value; +}], [dec, 4, "a", function (v) { + this.value = v; +}]], 0, _ => _Foo_brand.has(babelHelpers.checkInRHS(_))).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/public/exec.js new file mode 100644 index 000000000000..fa548d8d5c40 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/public/exec.js @@ -0,0 +1,103 @@ +function dec(value, context) { + context.addInitializer(function() { + this[context.name + '_' + context.kind + 'Context'] = context; + }); + + if (context.kind === 'getter') { + return function () { + return value.call(this) + 1; + } + } else { + return function (v) { + return value.call(this, v + 1); + } + } +} + +class Foo { + value = 1; + + @dec + get a() { + return this.value; + } + + @dec + set a(v) { + this.value = v; + } + + @dec + get ['b']() { + return this.value; + } + + @dec + set ['b'](v) { + this.value = v; + } +} + +let foo = new Foo(); + +const a_getterContext = foo['a_getterContext']; +const a_setterContext = foo['a_setterContext']; + +const b_getterContext = foo['b_getterContext']; +const b_setterContext = foo['b_setterContext']; + +expect(a_getterContext.access.has(foo)).toBe(true); +expect(a_getterContext.access.has({})).toBe(false); +expect(a_getterContext.access.has(Object.create(foo))).toBe(true); +expect(a_getterContext.access.has({ a: 1 })).toBe(true); +expect(a_getterContext.access.has(Object.create({ a: 1 }))).toBe(true); +expect(a_setterContext.access.has(foo)).toBe(true); +expect(a_setterContext.access.has({})).toBe(false); +expect(a_setterContext.access.has(Object.create(foo))).toBe(true); +expect(a_setterContext.access.has({ a: 1 })).toBe(true); +expect(a_setterContext.access.has(Object.create({ a: 1 }))).toBe(true); +expect(a_getterContext.access.has).not.toBe(a_setterContext.access.has); + +expect(foo.a).toBe(2); +expect(foo.b).toBe(2); +expect(a_getterContext.access.get(foo)).toBe(2); +expect(b_getterContext.access.get(foo)).toBe(2); +foo.a = 123; +expect(foo.a).toBe(125); +expect(foo.b).toBe(125); +expect(a_getterContext.access.get(foo)).toBe(125); +expect(b_getterContext.access.get(foo)).toBe(125); +foo.b = 456; +expect(foo.a).toBe(458); +expect(foo.b).toBe(458); +expect(a_getterContext.access.get(foo)).toBe(458); +expect(b_getterContext.access.get(foo)).toBe(458); +a_setterContext.access.set(foo, 789); +expect(foo.a).toBe(791); +expect(foo.b).toBe(791); +expect(a_getterContext.access.get(foo)).toBe(791); +expect(b_getterContext.access.get(foo)).toBe(791); + +expect(a_getterContext.name).toBe('a'); +expect(a_getterContext.kind).toBe('getter'); +expect(a_getterContext.static).toBe(false); +expect(a_getterContext.private).toBe(false); +expect(typeof a_getterContext.addInitializer).toBe('function'); + +expect(a_setterContext.name).toBe('a'); +expect(a_setterContext.kind).toBe('setter'); +expect(a_setterContext.static).toBe(false); +expect(a_setterContext.private).toBe(false); +expect(typeof a_setterContext.addInitializer).toBe('function'); + +expect(b_getterContext.name).toBe('b'); +expect(b_getterContext.kind).toBe('getter'); +expect(b_getterContext.static).toBe(false); +expect(b_getterContext.private).toBe(false); +expect(typeof b_getterContext.addInitializer).toBe('function'); + +expect(b_setterContext.name).toBe('b'); +expect(b_setterContext.kind).toBe('setter'); +expect(b_setterContext.static).toBe(false); +expect(b_setterContext.private).toBe(false); +expect(typeof b_setterContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/public/input.js new file mode 100644 index 000000000000..1af1569ba988 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/public/input.js @@ -0,0 +1,24 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + get a() { + return this.value; + } + + @dec + set a(v) { + this.value = v; + } + + @dec + get ['b']() { + return this.value; + } + + @dec + set ['b'](v) { + this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/public/output.js new file mode 100644 index 000000000000..6dc42b7e0bf1 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/public/output.js @@ -0,0 +1,22 @@ +var _Foo; +let _initProto; +const dec = () => {}; +class Foo { + constructor() { + babelHelpers.defineProperty(this, "value", (_initProto(this), 1)); + } + get a() { + return this.value; + } + set a(v) { + this.value = v; + } + get ['b']() { + return this.value; + } + set ['b'](v) { + this.value = v; + } +} +_Foo = Foo; +[_initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 3, "a"], [dec, 4, "a"], [dec, 3, 'b'], [dec, 4, 'b']]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-private/exec.js new file mode 100644 index 000000000000..c7faf2394242 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-private/exec.js @@ -0,0 +1,72 @@ +function dec(value, context) { + context.addInitializer(function() { + this[context.name + '_' + context.kind + 'Context'] = context; + }); + + if (context.kind === 'getter') { + return function () { + return value.call(this) + 1; + } + } else { + return function (v) { + return value.call(this, v + 1); + } + } +} + +class Foo { + static value = 1; + + @dec + static get #a() { + return this.value; + } + + @dec + static set #a(v) { + this.value = v; + } + + static getA() { + return this.#a; + } + + static setA(v) { + this.#a = v; + } +} + +const a_getterContext = Foo['#a_getterContext']; +const a_setterContext = Foo['#a_setterContext']; + +expect(a_getterContext.access.has(Foo)).toBe(true); +expect(a_getterContext.access.has({})).toBe(false); +expect(a_getterContext.access.has(Object.create(Foo))).toBe(false); +expect(a_setterContext.access.has(Foo)).toBe(true); +expect(a_setterContext.access.has({})).toBe(false); +expect(a_setterContext.access.has(Object.create(Foo))).toBe(false); +expect(a_getterContext.access.has).not.toBe(a_setterContext.access.has); + +expect(a_getterContext.access.get(Foo)).toBe(2); +expect(() => a_getterContext.access.get({})).toThrow(TypeError); +expect(Foo.getA()).toBe(2); +a_setterContext.access.set(Foo, 123); +expect(a_getterContext.access.get(Foo)).toBe(125); +expect(() => a_setterContext.access.set({}, 456)).toThrow(TypeError); +expect(a_getterContext.access.get(Foo)).toBe(125); +expect(Foo.getA()).toBe(125); +Foo.setA(456); +expect(a_getterContext.access.get(Foo)).toBe(458); +expect(Foo.getA()).toBe(458); + +expect(a_getterContext.name).toBe('#a'); +expect(a_getterContext.kind).toBe('getter'); +expect(a_getterContext.static).toBe(true); +expect(a_getterContext.private).toBe(true); +expect(typeof a_getterContext.addInitializer).toBe('function'); + +expect(a_setterContext.name).toBe('#a'); +expect(a_setterContext.kind).toBe('setter'); +expect(a_setterContext.static).toBe(true); +expect(a_setterContext.private).toBe(true); +expect(typeof a_setterContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-private/input.js new file mode 100644 index 000000000000..c832634c6b72 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-private/input.js @@ -0,0 +1,22 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static get #a() { + return this.value; + } + + @dec + static set #a(v) { + this.value = v; + } + + static getA() { + return this.#a; + } + + static setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-private/output.js new file mode 100644 index 000000000000..894b644911b3 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-private/output.js @@ -0,0 +1,21 @@ +var _Foo; +let _initStatic, _call_a, _call_a2; +const dec = () => {}; +class Foo { + static getA() { + return babelHelpers.classPrivateGetter(Foo, this, _call_a); + } + static setA(v) { + babelHelpers.classPrivateSetter(Foo, _call_a2, this, v); + } +} +_Foo = Foo; +(() => { + [_call_a, _call_a2, _initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 11, "a", function () { + return this.value; + }], [dec, 12, "a", function (v) { + this.value = v; + }]]).e; + _initStatic(_Foo); +})(); +babelHelpers.defineProperty(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-public/exec.js new file mode 100644 index 000000000000..9b4f9539e2e4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-public/exec.js @@ -0,0 +1,102 @@ +function dec(value, context) { + context.addInitializer(function() { + this[context.name + '_' + context.kind + 'Context'] = context; + }); + + if (context.kind === 'getter') { + return function () { + return value.call(this) + 1; + } + } else { + return function (v) { + return value.call(this, v + 1); + } + } +} + +class Foo { + static value = 1; + + @dec + static get a() { + return this.value; + } + + @dec + static set a(v) { + this.value = v; + } + + @dec + static get ['b']() { + return this.value; + } + + @dec + static set ['b'](v) { + this.value = v; + } +} + +const a_getterContext = Foo['a_getterContext']; +const a_setterContext = Foo['a_setterContext']; + +const b_getterContext = Foo['b_getterContext']; +const b_setterContext = Foo['b_setterContext']; + +expect(a_getterContext.access.has(Foo)).toBe(true); +expect(a_getterContext.access.has({})).toBe(false); +expect(a_getterContext.access.has(Object.create(Foo))).toBe(true); +expect(a_getterContext.access.has({ a: 1 })).toBe(true); +expect(a_getterContext.access.has(Object.create({ a: 1 }))).toBe(true); +expect(a_setterContext.access.has(Foo)).toBe(true); +expect(a_setterContext.access.has({})).toBe(false); +expect(a_setterContext.access.has(Object.create(Foo))).toBe(true); +expect(a_setterContext.access.has({ a: 1 })).toBe(true); +expect(a_setterContext.access.has(Object.create({ a: 1 }))).toBe(true); +expect(a_getterContext.access.has).not.toBe(a_setterContext.access.has); + +expect(Foo.a).toBe(2); +expect(Foo.b).toBe(2); +expect(a_getterContext.access.get(Foo)).toBe(2); +expect(b_getterContext.access.get(Foo)).toBe(2); +Foo.a = 123; +expect(Foo.a).toBe(125); +expect(Foo.b).toBe(125); +expect(a_getterContext.access.get(Foo)).toBe(125); +expect(b_getterContext.access.get(Foo)).toBe(125); +Foo.b = 456; +expect(Foo.a).toBe(458); +expect(Foo.b).toBe(458); +expect(a_getterContext.access.get(Foo)).toBe(458); +expect(b_getterContext.access.get(Foo)).toBe(458); +a_setterContext.access.set(Foo, 789); +expect(Foo.a).toBe(791); +expect(Foo.b).toBe(791); +expect(a_getterContext.access.get(Foo)).toBe(791); +expect(b_getterContext.access.get(Foo)).toBe(791); + +expect(a_getterContext.name).toBe('a'); +expect(a_getterContext.kind).toBe('getter'); +expect(a_getterContext.static).toBe(true); +expect(a_getterContext.private).toBe(false); +expect(typeof a_getterContext.addInitializer).toBe('function'); + +expect(a_setterContext.name).toBe('a'); +expect(a_setterContext.kind).toBe('setter'); +expect(a_setterContext.static).toBe(true); +expect(a_setterContext.private).toBe(false); +expect(typeof a_setterContext.addInitializer).toBe('function'); + +expect(b_getterContext.name).toBe('b'); +expect(b_getterContext.kind).toBe('getter'); +expect(b_getterContext.static).toBe(true); +expect(b_getterContext.private).toBe(false); +expect(typeof b_getterContext.addInitializer).toBe('function'); + +expect(b_setterContext.name).toBe('b'); +expect(b_setterContext.kind).toBe('setter'); +expect(b_setterContext.static).toBe(true); +expect(b_setterContext.private).toBe(false); +expect(typeof b_setterContext.addInitializer).toBe('function'); + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-public/input.js new file mode 100644 index 000000000000..bbad4af972ed --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-public/input.js @@ -0,0 +1,24 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static get a() { + return this.value; + } + + @dec + static set a(v) { + this.value = v; + } + + @dec + static get ['b']() { + return this.value; + } + + @dec + static set ['b'](v) { + this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-public/output.js new file mode 100644 index 000000000000..0ba260b4e582 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters--to-es2015/static-public/output.js @@ -0,0 +1,23 @@ +var _Foo; +let _initStatic; +const dec = () => {}; +class Foo { + static get a() { + return this.value; + } + static set a(v) { + this.value = v; + } + static get ['b']() { + return this.value; + } + static set ['b'](v) { + this.value = v; + } +} +_Foo = Foo; +(() => { + [_initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 11, "a"], [dec, 12, "a"], [dec, 11, 'b'], [dec, 12, 'b']]).e; + _initStatic(_Foo); +})(); +babelHelpers.defineProperty(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/options.json new file mode 100644 index 000000000000..4c274676d3c2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/private/input.js new file mode 100644 index 000000000000..fdf137cc4a64 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/private/input.js @@ -0,0 +1,22 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + get #a() { + return this.value; + } + + @dec + set #a(v) { + this.value = v; + } + + getA() { + return this.#a; + } + + setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/private/output.js new file mode 100644 index 000000000000..a8b135464ac6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/private/output.js @@ -0,0 +1,24 @@ +let _initProto, _call_a, _call_a2; +const dec = () => {}; +class Foo { + static { + [_call_a, _call_a2, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 3, "a", function () { + return this.value; + }], [dec, 4, "a", function (v) { + this.value = v; + }]], 0, _ => #a in _).e; + } + value = (_initProto(this), 1); + get #a() { + return _call_a(this); + } + set #a(v) { + _call_a2(this, v); + } + getA() { + return this.#a; + } + setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/public/input.js new file mode 100644 index 000000000000..1af1569ba988 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/public/input.js @@ -0,0 +1,24 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + get a() { + return this.value; + } + + @dec + set a(v) { + this.value = v; + } + + @dec + get ['b']() { + return this.value; + } + + @dec + set ['b'](v) { + this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/public/output.js new file mode 100644 index 000000000000..fa4339ee28bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/public/output.js @@ -0,0 +1,20 @@ +let _initProto; +const dec = () => {}; +class Foo { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 3, "a"], [dec, 4, "a"], [dec, 3, 'b'], [dec, 4, 'b']]).e; + } + value = (_initProto(this), 1); + get a() { + return this.value; + } + set a(v) { + this.value = v; + } + get ['b']() { + return this.value; + } + set ['b'](v) { + this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-private/input.js new file mode 100644 index 000000000000..c832634c6b72 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-private/input.js @@ -0,0 +1,22 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static get #a() { + return this.value; + } + + @dec + static set #a(v) { + this.value = v; + } + + static getA() { + return this.#a; + } + + static setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-private/output.js new file mode 100644 index 000000000000..6671caa1a857 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-private/output.js @@ -0,0 +1,25 @@ +let _initStatic, _call_a, _call_a2; +const dec = () => {}; +class Foo { + static { + [_call_a, _call_a2, _initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 11, "a", function () { + return this.value; + }], [dec, 12, "a", function (v) { + this.value = v; + }]]).e; + _initStatic(this); + } + static value = 1; + static get #a() { + return _call_a(this); + } + static set #a(v) { + _call_a2(this, v); + } + static getA() { + return this.#a; + } + static setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-public/input.js new file mode 100644 index 000000000000..bbad4af972ed --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-public/input.js @@ -0,0 +1,24 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static get a() { + return this.value; + } + + @dec + static set a(v) { + this.value = v; + } + + @dec + static get ['b']() { + return this.value; + } + + @dec + static set ['b'](v) { + this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-public/output.js new file mode 100644 index 000000000000..21208415ec1c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters-and-setters/static-public/output.js @@ -0,0 +1,21 @@ +let _initStatic; +const dec = () => {}; +class Foo { + static { + [_initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 11, "a"], [dec, 12, "a"], [dec, 11, 'b'], [dec, 12, 'b']]).e; + _initStatic(this); + } + static value = 1; + static get a() { + return this.value; + } + static set a(v) { + this.value = v; + } + static get ['b']() { + return this.value; + } + static set ['b'](v) { + this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/exec.js new file mode 100644 index 000000000000..5e7003b637d8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static get a() {}; + @dec static get #a() {}; + + @dec static get "b"() {} + @dec static get ["c"]() {}; + + @dec static get 0() {}; + @dec static get [1]() {}; + + @dec static get 2n() {}; + @dec static get [3n]() {}; + + @dec static get [f()]() {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/input.js new file mode 100644 index 000000000000..5e7003b637d8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static get a() {}; + @dec static get #a() {}; + + @dec static get "b"() {} + @dec static get ["c"]() {}; + + @dec static get 0() {}; + @dec static get [1]() {}; + + @dec static get 2n() {}; + @dec static get [3n]() {}; + + @dec static get [f()]() {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/output.js new file mode 100644 index 000000000000..164cf8cf28cb --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/context-name/output.js @@ -0,0 +1,29 @@ +let _initStatic, _call_a, _computedKey; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +class Foo { + static { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 11, "a"], [dec, 11, "a", function () {}], [dec, 11, "b"], [dec, 11, "c"], [dec, 11, 0], [dec, 11, 1], [dec, 11, 2n], [dec, 11, 3n], [dec, 11, _computedKey]]).e; + _initStatic(this); + } + static get a() {} + static get #a() { + return _call_a(this); + } + static get "b"() {} + static get ["c"]() {} + static get 0() {} + static get [1]() {} + static get 2n() {} + static get [3n]() {} + static get [_computedKey = babelHelpers.toPropertyKey(f())]() {} +} +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/options.json new file mode 100644 index 000000000000..4c274676d3c2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/private/input.js new file mode 100644 index 000000000000..28519502bf46 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + get #a() { + return this.value; + } + + getA() { + return this.#a; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/private/output.js new file mode 100644 index 000000000000..1c418f65be5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/private/output.js @@ -0,0 +1,16 @@ +let _initProto, _call_a; +const dec = () => {}; +class Foo { + static { + [_call_a, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 3, "a", function () { + return this.value; + }]], 0, _ => #a in _).e; + } + value = (_initProto(this), 1); + get #a() { + return _call_a(this); + } + getA() { + return this.#a; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/public/input.js new file mode 100644 index 000000000000..392f9e03412f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + get a() { + return this.value; + } + + @dec + get ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/public/output.js new file mode 100644 index 000000000000..dae495aab135 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/public/output.js @@ -0,0 +1,14 @@ +let _initProto; +const dec = () => {}; +class Foo { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 3, "a"], [dec, 3, 'b']]).e; + } + value = (_initProto(this), 1); + get a() { + return this.value; + } + get ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-private/input.js new file mode 100644 index 000000000000..9d64c02982da --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static get #a() { + return this.value; + } + + static getA() { + return this.#a; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-private/output.js new file mode 100644 index 000000000000..94e00b97a948 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-private/output.js @@ -0,0 +1,17 @@ +let _initStatic, _call_a; +const dec = () => {}; +class Foo { + static { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 11, "a", function () { + return this.value; + }]]).e; + _initStatic(this); + } + static value = 1; + static get #a() { + return _call_a(this); + } + static getA() { + return this.#a; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-public/input.js new file mode 100644 index 000000000000..3bc53fb17cc5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static get a() { + return this.value; + } + + @dec + static get ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-public/output.js new file mode 100644 index 000000000000..cb11c9b5b9d3 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-getters/static-public/output.js @@ -0,0 +1,15 @@ +let _initStatic; +const dec = () => {}; +class Foo { + static { + [_initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 11, "a"], [dec, 11, 'b']]).e; + _initStatic(this); + } + static value = 1; + static get a() { + return this.value; + } + static get ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/exec.js new file mode 100644 index 000000000000..fbca295841be --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static a() {}; + @dec static #a() {}; + + @dec static "b"() {} + @dec static ["c"]() {}; + + @dec static 0() {}; + @dec static [1]() {}; + + @dec static 2n() {}; + @dec static [3n]() {}; + + @dec static [f()]() {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/input.js new file mode 100644 index 000000000000..fbca295841be --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static a() {}; + @dec static #a() {}; + + @dec static "b"() {} + @dec static ["c"]() {}; + + @dec static 0() {}; + @dec static [1]() {}; + + @dec static 2n() {}; + @dec static [3n]() {}; + + @dec static [f()]() {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/options.json new file mode 100644 index 000000000000..e6953fa50f0b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "14.6.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/output.js new file mode 100644 index 000000000000..017b3a68db21 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/context-name/output.js @@ -0,0 +1,32 @@ +var _Foo; +let _initStatic, _call_a, _computedKey; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +_computedKey = babelHelpers.toPropertyKey(f()); +class Foo { + static a() {} + static "b"() {} + static ["c"]() {} + static 0() {} + static [1]() {} + static 2n() {} + static [3n]() {} + static [_computedKey]() {} +} +_Foo = Foo; +(() => { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 10, "a"], [dec, 10, "a", function () {}], [dec, 10, "b"], [dec, 10, "c"], [dec, 10, 0], [dec, 10, 1], [dec, 10, 2n], [dec, 10, 3n], [dec, 10, _computedKey]]).e; + _initStatic(_Foo); +})(); +var _a = { + _: _call_a +}; +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/exec.js new file mode 100644 index 000000000000..8e4f3c2207bf --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/exec.js @@ -0,0 +1,23 @@ +let counter = 0; + +class Foo { + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("AsyncFunction"); + }) + async #a() {} + + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("GeneratorFunction"); + }) + *#g() {} + + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("AsyncGeneratorFunction"); + }) + async *#ag() {} +} + +expect(counter).toBe(3); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/input.js new file mode 100644 index 000000000000..4a680503322e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/input.js @@ -0,0 +1,10 @@ +class Foo { + @dec + async #a() {} + + @dec + *#g() {} + + @dec + async *#ag() {} +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/options.json new file mode 100644 index 000000000000..2b597fab65dd --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "10.0.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/output.js new file mode 100644 index 000000000000..334e9d50349b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-async-and-generator/output.js @@ -0,0 +1,15 @@ +var _Foo; +let _initProto, _call_a, _call_g, _call_ag; +var _ag = /*#__PURE__*/new WeakMap(); +var _g = /*#__PURE__*/new WeakMap(); +var _a = /*#__PURE__*/new WeakMap(); +class Foo { + constructor() { + babelHelpers.classPrivateFieldInitSpec(this, _ag, _call_ag); + babelHelpers.classPrivateFieldInitSpec(this, _g, _call_g); + babelHelpers.classPrivateFieldInitSpec(this, _a, _call_a); + _initProto(this); + } +} +_Foo = Foo; +[_call_a, _call_g, _call_ag, _initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 2, "a", async function () {}], [dec, 2, "g", function* () {}], [dec, 2, "ag", async function* () {}]], 0, _ => _a.has(babelHelpers.checkInRHS(_))).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-with-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-with-initializers/exec.js new file mode 100644 index 000000000000..f54ef825ce1a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private-with-initializers/exec.js @@ -0,0 +1,45 @@ +function dec(fn, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(fn.name).toEqual(context.name); + return function () { + return fn.call(this) + 1; + } +} + +class Foo { + value = 1; + + @dec + #a() { + return this.value; + } + + callA() { + return this.#a(); + } +} + +let foo = new Foo(); + +const aContext = foo['#aContext']; + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(false); + +// First call gets the method, second call calls the method with correct `this` +expect(aContext.access.get(foo).call(foo)).toBe(2); +expect(() => aContext.access.get({})).toThrow(TypeError); +expect(foo.callA()).toBe(2); +foo.value = 123; +expect(aContext.access.get(foo).call(foo)).toBe(124); +expect(foo.callA()).toBe(124); + +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('method'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private/exec.js new file mode 100644 index 000000000000..d766ded54c1e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private/exec.js @@ -0,0 +1,30 @@ +let aContext; + +function dec(fn, context) { + expect(fn.name).toEqual(context.name); + if (!aContext) aContext = context; + return function () { + return fn.call(this) + 1; + } +} + +class Foo { + value = 1; + + @dec + #a() { + return this.value; + } + + callA() { + return this.#a(); + } +} + +let foo = new Foo(); + +expect(aContext.access).not.toHaveProperty("set"); + +expect(foo.callA()).toBe(2); +foo.value = 123; +expect(foo.callA()).toBe(124); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private/input.js new file mode 100644 index 000000000000..098bbbb687f2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + #a() { + return this.value; + } + + callA() { + return this.#a(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private/output.js new file mode 100644 index 000000000000..482f378a16d1 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/private/output.js @@ -0,0 +1,17 @@ +var _Foo; +let _initProto, _call_a; +const dec = () => {}; +var _a = /*#__PURE__*/new WeakMap(); +class Foo { + constructor() { + babelHelpers.classPrivateFieldInitSpec(this, _a, _call_a); + babelHelpers.defineProperty(this, "value", (_initProto(this), 1)); + } + callA() { + return babelHelpers.classPrivateFieldGet2(_a, this).call(this); + } +} +_Foo = Foo; +[_call_a, _initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 2, "a", function () { + return this.value; +}]], 0, _ => _a.has(babelHelpers.checkInRHS(_))).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public-with-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public-with-initializers/exec.js new file mode 100644 index 000000000000..5fead21939c2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public-with-initializers/exec.js @@ -0,0 +1,60 @@ +function dec(fn, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(fn.name).toEqual(context.name); + return function () { + return fn.call(this) + 1; + } +} + +class Foo { + value = 1; + + @dec + a() { + return this.value; + } + + @dec + ['b']() { + return this.value; + } +} + +let foo = new Foo(); + +const aContext = foo['aContext']; +const bContext = foo['bContext']; + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(foo.a()).toBe(2); +expect(aContext.access.get(foo).call(foo)).toBe(2); +expect(foo.b()).toBe(2); +expect(bContext.access.get(foo).call(foo)).toBe(2); +foo.value = 123; +expect(aContext.access.get(foo).call(foo)).toBe(124); +expect(foo.a()).toBe(124); +expect(bContext.access.get(foo).call(foo)).toBe(124); +expect(foo.b()).toBe(124); + +expect(aContext.access.get({})).toBe(undefined); +expect(aContext.access.get({ a: 3 })).toBe(3); + +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('method'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('method'); +expect(bContext.static).toBe(false); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public/exec.js new file mode 100644 index 000000000000..d8f733ec0e96 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public/exec.js @@ -0,0 +1,33 @@ +let aContext; + +function dec(fn, context) { + expect(fn.name).toEqual(context.name); + if (!aContext) aContext = context; + return function () { + return fn.call(this) + 1; + } +} + +class Foo { + value = 1; + + @dec + a() { + return this.value; + } + + @dec + ['b']() { + return this.value; + } +} + +let foo = new Foo(); + +expect(aContext.access).not.toHaveProperty("set"); + +expect(foo.a()).toBe(2); +expect(foo.b()).toBe(2); +foo.value = 123; +expect(foo.a()).toBe(124); +expect(foo.b()).toBe(124); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public/input.js new file mode 100644 index 000000000000..3a7f4cfaae9c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + a() { + return this.value; + } + + @dec + ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public/output.js new file mode 100644 index 000000000000..d9c9e3e131c0 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/public/output.js @@ -0,0 +1,16 @@ +var _Foo; +let _initProto; +const dec = () => {}; +class Foo { + constructor() { + babelHelpers.defineProperty(this, "value", (_initProto(this), 1)); + } + a() { + return this.value; + } + ['b']() { + return this.value; + } +} +_Foo = Foo; +[_initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 2, "a"], [dec, 2, 'b']]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private-with-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private-with-initializers/exec.js new file mode 100644 index 000000000000..5cdcd7322a16 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private-with-initializers/exec.js @@ -0,0 +1,43 @@ +function dec(fn, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(fn.name).toEqual(context.name); + return function () { + return fn.call(this) + 1; + } +} + +class Foo { + static value = 1; + + @dec + static #a() { + return this.value; + } + + static callA() { + return this.#a(); + } +} + +const aContext = Foo['#aContext']; + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(false); + +// First call gets the method, second call calls the method with correct `this` +expect(aContext.access.get(Foo).call(Foo)).toBe(2); +expect(() => aContext.access.get({})).toThrow(TypeError); +expect(Foo.callA()).toBe(2); +Foo.value = 123; +expect(aContext.access.get(Foo).call(Foo)).toBe(124); +expect(Foo.callA()).toBe(124); + +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('method'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private/exec.js new file mode 100644 index 000000000000..76ee192448b6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private/exec.js @@ -0,0 +1,28 @@ +let aContext; + +function dec(fn, context) { + expect(fn.name).toEqual(context.name); + if (!aContext) aContext = context; + return function () { + return fn.call(this) + 1; + } +} + +class Foo { + static value = 1; + + @dec + static #a() { + return this.value; + } + + static callA() { + return this.#a(); + } +} + +expect(aContext.access).not.toHaveProperty("set"); + +expect(Foo.callA()).toBe(2); +Foo.value = 123; +expect(Foo.callA()).toBe(124); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private/input.js new file mode 100644 index 000000000000..4a6ae5d4d7fd --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static #a() { + return this.value; + } + + static callA() { + return this.#a(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private/output.js new file mode 100644 index 000000000000..92cda9d8e26e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-private/output.js @@ -0,0 +1,19 @@ +var _Foo; +let _initStatic, _call_a; +const dec = () => {}; +class Foo { + static callA() { + return babelHelpers.assertClassBrand(Foo, this, _a)._.call(this); + } +} +_Foo = Foo; +(() => { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 10, "a", function () { + return this.value; + }]]).e; + _initStatic(_Foo); +})(); +var _a = { + _: _call_a +}; +babelHelpers.defineProperty(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public-with-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public-with-initializers/exec.js new file mode 100644 index 000000000000..570446cde6f9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public-with-initializers/exec.js @@ -0,0 +1,55 @@ +function dec(fn, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(fn.name).toEqual(context.name); + return function () { + return fn.call(this) + 1; + } +} + +class Foo { + static value = 1; + + @dec + static a() { + return this.value; + } + + @dec + static ['b']() { + return this.value; + } +} + +const aContext = Foo['aContext']; +const bContext = Foo['bContext']; + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(Foo.a()).toBe(2); +expect(aContext.access.get(Foo).call(Foo)).toBe(2); +expect(Foo.b()).toBe(2); +expect(bContext.access.get(Foo).call(Foo)).toBe(2); +Foo.value = 123; +expect(aContext.access.get(Foo).call(Foo)).toBe(124); +expect(Foo.a()).toBe(124); +expect(bContext.access.get(Foo).call(Foo)).toBe(124); +expect(Foo.b()).toBe(124); + +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('method'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('method'); +expect(bContext.static).toBe(true); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public/exec.js new file mode 100644 index 000000000000..26e7ff852c81 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public/exec.js @@ -0,0 +1,31 @@ +let aContext; + +function dec(fn, context) { + expect(fn.name).toEqual(context.name); + if (!aContext) aContext = context; + return function () { + return fn.call(this) + 1; + } +} + +class Foo { + static value = 1; + + @dec + static a() { + return this.value; + } + + @dec + static ['b']() { + return this.value; + } +} + +expect(aContext.access).not.toHaveProperty("set"); + +expect(Foo.a()).toBe(2); +expect(Foo.b()).toBe(2); +Foo.value = 123; +expect(Foo.a()).toBe(124); +expect(Foo.b()).toBe(124); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public/input.js new file mode 100644 index 000000000000..5f81da5c0405 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static a() { + return this.value; + } + + @dec + static ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public/output.js new file mode 100644 index 000000000000..b1aac8df7aca --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods--to-es2015/static-public/output.js @@ -0,0 +1,17 @@ +var _Foo; +let _initStatic; +const dec = () => {}; +class Foo { + static a() { + return this.value; + } + static ['b']() { + return this.value; + } +} +_Foo = Foo; +(() => { + [_initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 10, "a"], [dec, 10, 'b']]).e; + _initStatic(_Foo); +})(); +babelHelpers.defineProperty(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/exec.js new file mode 100644 index 000000000000..fbca295841be --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static a() {}; + @dec static #a() {}; + + @dec static "b"() {} + @dec static ["c"]() {}; + + @dec static 0() {}; + @dec static [1]() {}; + + @dec static 2n() {}; + @dec static [3n]() {}; + + @dec static [f()]() {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/input.js new file mode 100644 index 000000000000..fbca295841be --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static a() {}; + @dec static #a() {}; + + @dec static "b"() {} + @dec static ["c"]() {}; + + @dec static 0() {}; + @dec static [1]() {}; + + @dec static 2n() {}; + @dec static [3n]() {}; + + @dec static [f()]() {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/output.js new file mode 100644 index 000000000000..fa80ef6939f8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/context-name/output.js @@ -0,0 +1,27 @@ +let _initStatic, _call_a, _computedKey; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +class Foo { + static { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 10, "a"], [dec, 10, "a", function () {}], [dec, 10, "b"], [dec, 10, "c"], [dec, 10, 0], [dec, 10, 1], [dec, 10, 2n], [dec, 10, 3n], [dec, 10, _computedKey]]).e; + _initStatic(this); + } + static #a = _call_a; + static a() {} + static "b"() {} + static ["c"]() {} + static 0() {} + static [1]() {} + static 2n() {} + static [3n]() {} + static [_computedKey = babelHelpers.toPropertyKey(f())]() {} +} +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/options.json new file mode 100644 index 000000000000..4c274676d3c2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/exec.js new file mode 100644 index 000000000000..8e4f3c2207bf --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/exec.js @@ -0,0 +1,23 @@ +let counter = 0; + +class Foo { + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("AsyncFunction"); + }) + async #a() {} + + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("GeneratorFunction"); + }) + *#g() {} + + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("AsyncGeneratorFunction"); + }) + async *#ag() {} +} + +expect(counter).toBe(3); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/input.js new file mode 100644 index 000000000000..4a680503322e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/input.js @@ -0,0 +1,10 @@ +class Foo { + @dec + async #a() {} + + @dec + *#g() {} + + @dec + async *#ag() {} +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/output.js new file mode 100644 index 000000000000..341876d31bce --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private-async-and-generator/output.js @@ -0,0 +1,12 @@ +let _initProto, _call_a, _call_g, _call_ag; +class Foo { + static { + [_call_a, _call_g, _call_ag, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "a", async function () {}], [dec, 2, "g", function* () {}], [dec, 2, "ag", async function* () {}]], 0, _ => #a in _).e; + } + constructor() { + _initProto(this); + } + #ag = _call_ag; + #g = _call_g; + #a = _call_a; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private/input.js new file mode 100644 index 000000000000..098bbbb687f2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + #a() { + return this.value; + } + + callA() { + return this.#a(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private/output.js new file mode 100644 index 000000000000..1e4477b149d8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/private/output.js @@ -0,0 +1,14 @@ +let _initProto, _call_a; +const dec = () => {}; +class Foo { + static { + [_call_a, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "a", function () { + return this.value; + }]], 0, _ => #a in _).e; + } + #a = _call_a; + value = (_initProto(this), 1); + callA() { + return this.#a(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/public/input.js new file mode 100644 index 000000000000..3a7f4cfaae9c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + a() { + return this.value; + } + + @dec + ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/public/output.js new file mode 100644 index 000000000000..4fa18403733d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/public/output.js @@ -0,0 +1,14 @@ +let _initProto; +const dec = () => {}; +class Foo { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "a"], [dec, 2, 'b']]).e; + } + value = (_initProto(this), 1); + a() { + return this.value; + } + ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-private/input.js new file mode 100644 index 000000000000..4a6ae5d4d7fd --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static #a() { + return this.value; + } + + static callA() { + return this.#a(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-private/output.js new file mode 100644 index 000000000000..c2b38124813e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-private/output.js @@ -0,0 +1,15 @@ +let _initStatic, _call_a; +const dec = () => {}; +class Foo { + static { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 10, "a", function () { + return this.value; + }]]).e; + _initStatic(this); + } + static #a = _call_a; + static value = 1; + static callA() { + return this.#a(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-public/input.js new file mode 100644 index 000000000000..5f81da5c0405 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static a() { + return this.value; + } + + @dec + static ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-public/output.js new file mode 100644 index 000000000000..2cb123fa3188 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-methods/static-public/output.js @@ -0,0 +1,15 @@ +let _initStatic; +const dec = () => {}; +class Foo { + static { + [_initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 10, "a"], [dec, 10, 'b']]).e; + _initStatic(this); + } + static value = 1; + static a() { + return this.value; + } + static ['b']() { + return this.value; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-and-method-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-and-method-decorators/exec.js new file mode 100644 index 000000000000..11aae499cb0d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-and-method-decorators/exec.js @@ -0,0 +1,77 @@ +function dec() {} + +var i = 0; +var log = []; + +function push(x) { log.push(x); return x; } + +function decWithInitializer(_, { addInitializer }) { + addInitializer(() => push(i++) ); +} + +new @dec class C1 { + @dec static m() {} +} + +new @dec class C2 { + @dec static #m() {} +} + +new @dec class C3 { + @dec m() {} +} + +new @dec class C4 { + @dec #m() {} +} + +new @decWithInitializer class C5 { + @dec static m() {} +} + +new @decWithInitializer class C6 { + @dec static #m() {} +} + +new @decWithInitializer class C7 { + @dec m() {} +} + +new @decWithInitializer class C8 { + @dec #m() {} +} + +new @dec class C9 { + @decWithInitializer static m() {} +} + +new @dec class C10 { + @decWithInitializer static #m() {} +} + +new @dec class C11 { + @decWithInitializer m() {} +} + +new @dec class C12 { + @decWithInitializer #m() {} +} + +new @decWithInitializer class C13 { + @decWithInitializer static m() {} +} + +new @decWithInitializer class C14 { + @decWithInitializer static #m() {} +} + +new @decWithInitializer class C15 { + @decWithInitializer m() {} +} + +new @decWithInitializer class C16 { + @decWithInitializer #m() {} +} + +var nums = Array.from({ length: 16 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-and-property-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-and-property-decorators/exec.js new file mode 100644 index 000000000000..3993d925adec --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-and-property-decorators/exec.js @@ -0,0 +1,45 @@ +function dec() {} + +var i = 0; +var log = []; + +function push(x) { log.push(x); return x; } + +function decWithInitializer(_, { addInitializer }) { + addInitializer(() => push(i++) ); +} + +new @dec class C1 { + @dec static p +} + +new @dec class C2 { + @dec static #p +} + +new @dec class C3 { + @dec p +} + +new @dec class C4 { + @dec #p +} + +new @decWithInitializer class C5 { + @dec static p +} + +new @decWithInitializer class C6 { + @dec static #p +} + +new @decWithInitializer class C7 { + @dec p +} + +new @decWithInitializer class C8 { + @dec #p +} + +var nums = Array.from({ length: 4 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-in-for-loop/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-in-for-loop/exec.js new file mode 100644 index 000000000000..1074cab15fb5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-in-for-loop/exec.js @@ -0,0 +1,94 @@ +{ + const logs = []; + const classes = []; + const noop = () => {} + + for (let i = 0; i < 2; i++) { + classes.push(class C { + @noop [i]; + }) + } + + for (const clazz of classes) { + logs.push(Reflect.ownKeys(new clazz())); + } + + expect(logs.join()).toBe("0,1"); +} + +{ + const logs = []; + const classes = []; + const noop = () => {} + + for (let i = 0; i < 2; i++) { + classes.push(@noop class C { + [i]; + }) + } + + for (const clazz of classes) { + logs.push(Reflect.ownKeys(new clazz())); + } + + expect(logs.join()).toBe("0,1"); +} + +{ + const logs = []; + const classes = []; + const noop = () => {} + + for (let i = 0; i < 2; i++) { + classes.push(@noop class C { + @noop [i]; + }) + } + + for (const clazz of classes) { + logs.push(Reflect.ownKeys(new clazz())); + } + + expect(logs.join()).toBe("0,1"); +} + +{ + const logs = []; + const classes = []; + const setValueTo = i => () => () => i + + for (let i = 0; i < 2; i++) { + classes.push(class C { + @setValueTo(i) [i]; + }) + } + + for (const clazz of classes) { + const c = new clazz(); + const key = Reflect.ownKeys(c)[0]; + logs.push([key, c[key]].join(":")); + } + + expect(logs.join()).toBe("0:0,1:1"); +} + +{ + const logs = []; + const classes = []; + const noop = () => {} + const setValueTo = i => (_, { access, addInitializer }) => addInitializer(function() { access.set(this, i) }) + + for (let i = 0; i < 2; i++) { + classes.push(@noop class C { + @setValueTo(i) [i]; + }) + } + + for (const clazz of classes) { + const c = new clazz(); + const key = Reflect.ownKeys(c)[0]; + logs.push([key, c[key]].join(":")); + } + + expect(logs.join()).toBe("0:0,1:1"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-underscore-property/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-underscore-property/exec.js new file mode 100644 index 000000000000..bc28d94fb7b4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/class-underscore-property/exec.js @@ -0,0 +1,52 @@ +function noopFactory() { return function noop() {} } + +{ + class B { + @noopFactory() + static _ = "B"; + } + + class C extends B { + @noopFactory() #p; + } + + expect(C._).toBe("B"); +} + +{ + class B { + @noopFactory() + static _ = "B"; + } + + @noopFactory() + class C extends B { + @noopFactory() #p; + } + + expect(C._).toBe("B"); +} + +{ + class C { + @noopFactory() #p; + } + + expect(Reflect.ownKeys(C)).not.toContain("_"); +} + +{ + @noopFactory() + class C {} + + expect(Reflect.ownKeys(C)).not.toContain("_"); +} + +{ + @noopFactory() + class C { + @noopFactory() #p; + } + + expect(Reflect.ownKeys(C)).not.toContain("_"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/ctx-access-public-other-this/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/ctx-access-public-other-this/exec.js new file mode 100644 index 000000000000..8542e671a413 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/ctx-access-public-other-this/exec.js @@ -0,0 +1,39 @@ +function dec(v, context) { + context.addInitializer(function () { + this[context.name + 'Context'] = context; + }); + + return v; +} + +class Foo { + @dec + static accessor a; + + _b = 1; + + @dec + set b(v) { + this._b = v + 1; + } +} + +const obj = {}; +const foo = new Foo(); + +const aContext = Foo.aContext; +const bContext = foo.bContext; + +aContext.access.set(Foo, 123); + +bContext.access.set(foo, 123); + + +aContext.access.set(obj, 456); +bContext.access.set(obj, 456); + +expect(Foo.a).toBe(123); +expect(foo._b).toBe(124); + +expect(obj.a).toBe(456); +expect(obj.b).toBe(456); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-arguments/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-arguments/exec.js new file mode 100644 index 000000000000..bb1cd1c259f4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-arguments/exec.js @@ -0,0 +1,54 @@ +{ + let receivedArguments; + function decFactory(args) { + receivedArguments = args; + return x => x; + } + function B() { + class C { + @decFactory(arguments) #p; + } + } + + B(0); + expect(receivedArguments).toHaveLength(1); + expect(receivedArguments[0]).toBe(0); +} + +{ + function noop() {} + let receivedArguments; + function decFactory(args) { + receivedArguments = args; + return x => x; + } + function B() { + @noop + class C { + @decFactory(arguments) #p; + } + } + + B(0); + expect(receivedArguments).toHaveLength(1); + expect(receivedArguments[0]).toBe(0); +} + +{ + function noop() {} + let receivedArguments; + function decFactory(args) { + receivedArguments = args; + return x => x; + } + function B() { + @noop + class C { + @decFactory(arguments) static #p; + } + } + + B(0); + expect(receivedArguments).toHaveLength(1); + expect(receivedArguments[0]).toBe(0); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-new-target/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-new-target/exec.js new file mode 100644 index 000000000000..06643188b21c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-new-target/exec.js @@ -0,0 +1,54 @@ +{ + let receivedNewTarget; + function decFactory(target) { + receivedNewTarget = target; + return x => x; + } + function B() { + class C { + @decFactory(new.target) #p; + } + } + + new B(); + + expect(receivedNewTarget).toBe(B); +} + +{ + function noop() {} + let receivedNewTarget; + function decFactory(target) { + receivedNewTarget = target; + return x => x; + } + function B() { + @noop + class C { + @decFactory(new.target) #p; + } + } + + new B(); + + expect(receivedNewTarget).toBe(B); +} + +{ + function noop() {} + let receivedNewTarget; + function decFactory(target) { + receivedNewTarget = target; + return x => x; + } + function B() { + @noop + class C { + @decFactory(new.target) static #p; + } + } + + new B(); + + expect(receivedNewTarget).toBe(B); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-private-environment/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-private-environment/exec.js new file mode 100644 index 000000000000..4ae3da714ae6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-private-environment/exec.js @@ -0,0 +1,159 @@ +{ + let staticFns = [], fns = [] + let B; + + function capture(staticFn, fn) { + staticFns.push(staticFn); + fns.push(fn); + } + + function dummy() {} + + class A { + static #X = "A#X"; + #x = "a#x"; + constructor () { + B = class B { + static #X = "B#X"; + #x = "b#x"; + @(capture(_ => _.#X, _ => _.#x), dummy) method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) get getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static get getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) set setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) static set setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) property; + @(capture(_ => _.#X, _ => _.#x), dummy) static property; + @(capture(_ => _.#X, _ => _.#x), dummy) accessor accessor; + @(capture(_ => _.#X, _ => _.#x), dummy) static accessor accessor; + } + } + } + + let a = new A(), b = new B(); + + expect(staticFns.map(fn => fn(B)).join()).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); + expect(fns.map(fn => fn(b)).join()).toBe("b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x"); +} + +{ + let staticFns = [], fns = [] + let B; + + function capture(staticFn, fn) { + staticFns.push(staticFn); + fns.push(fn); + } + + function dummy() {} + + class A { + static #X = "A#X"; + #x = "a#x"; + constructor () { + B = class B { + static #X = "B#X"; + #x = "b#x"; + @(capture(_ => _.#X, _ => _.#x), dummy) #method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static #Method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) get #getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static get #Getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) set #setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) static set #Setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) #property; + @(capture(_ => _.#X, _ => _.#x), dummy) static #Property; + @(capture(_ => _.#X, _ => _.#x), dummy) accessor #accessor; + @(capture(_ => _.#X, _ => _.#x), dummy) static accessor #Accessor; + } + } + } + + let a = new A(), b = new B(); + + expect(staticFns.map(fn => fn(B)).join()).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); + expect(fns.map(fn => fn(b)).join()).toBe("b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x"); +} + +{ + let staticFns = [], fns = [] + let B; + + function capture(staticFn, fn) { + staticFns.push(staticFn); + fns.push(fn); + } + + function dummy() {} + + class A { + static #X = "A#X"; + #x = "a#x"; + constructor () { + B = + @(capture(_ => _.#X, _ => _.#x), dummy) + class B { + static #X = "B#X"; + #x = "b#x"; + @(capture(_ => _.#X, _ => _.#x), dummy) method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) get getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static get getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) set setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) static set setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) property; + @(capture(_ => _.#X, _ => _.#x), dummy) static property; + @(capture(_ => _.#X, _ => _.#x), dummy) accessor accessor; + @(capture(_ => _.#X, _ => _.#x), dummy) static accessor accessor; + } + } + } + + let a = new A(), b = new B(); + expect(staticFns.shift()(A)).toBe("A#X"); + expect(fns.shift()(a)).toBe("a#x"); + + expect(staticFns.map(fn => fn(B)).join()).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); + expect(fns.map(fn => fn(b)).join()).toBe("b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x"); +} + +{ + let staticFns = [], fns = [] + let B; + + function capture(staticFn, fn) { + staticFns.push(staticFn); + fns.push(fn); + } + + function dummy() {} + + class A { + static #X = "A#X"; + #x = "a#x"; + constructor () { + B = + @(capture(_ => _.#X, _ => _.#x), dummy) + class B { + static #X = "B#X"; + #x = "b#x"; + @(capture(_ => _.#X, _ => _.#x), dummy) #method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static #Method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) get #getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static get #Getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) set #setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) static set #Setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) #property; + @(capture(_ => _.#X, _ => _.#x), dummy) static #Property; + @(capture(_ => _.#X, _ => _.#x), dummy) accessor #accessor; + @(capture(_ => _.#X, _ => _.#x), dummy) static accessor #Accessor; + } + } + } + + let a = new A(), b = new B(); + expect(staticFns.shift()(A)).toBe("A#X"); + expect(fns.shift()(a)).toBe("a#x"); + + expect(staticFns.map(fn => fn(B)).join()).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); + expect(fns.map(fn => fn(b)).join()).toBe("b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-super-getter-setter/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-super-getter-setter/exec.js new file mode 100644 index 000000000000..816f371e0268 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-super-getter-setter/exec.js @@ -0,0 +1,159 @@ +function noop() {} + +function BaseFactory(logs) { + return class A { + static get getter() { + logs.push("getter") + } + static set setter(v) { + logs.push("setter"); + } + } +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + class C { + @(super.setter = super.getter, noop) p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + class C { + @(super.setter = super.getter, noop) #p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + class C { + @(super.setter = super.getter, noop) accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) static p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) #p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) static [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) static accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-super-property/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-super-property/exec.js new file mode 100644 index 000000000000..2ba4461a451f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-super-property/exec.js @@ -0,0 +1,148 @@ +function noop() {} + +{ + let receivedName; + class B extends class A {} { + static m() { + class C { + @(receivedName = super.name, noop) p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + class C { + @(receivedName = super.name, noop) #p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + class C { + @(receivedName = super.name, noop) accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) static p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) #p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) static [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) static accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-this/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-this/exec.js new file mode 100644 index 000000000000..d424d5679805 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-this/exec.js @@ -0,0 +1,61 @@ +{ + let receivedName; + function decFactory(name) { + receivedName = name; + return x => x; + } + class B { + static m() { + class C { + @decFactory(this.name) #p; + } + } + } + + B.m(); + expect(receivedName).toBe("B"); +} + +{ + let receivedLength; + function decFactory(length) { + receivedLength = length; + return x => x; + } + function noop() {} + class B { + static m() { + @noop + class C { + @decFactory(this.length) #p; + constructor(bar) {} + } + } + constructor(foo, bar) {} + } + + B.m(); + expect(receivedLength).toBe(2); +} + +{ + let receivedLength; + function decFactory(length) { + receivedLength = length; + return x => x; + } + function noop() {} + class B { + static m() { + @noop + class C { + @decFactory(this.length) static #p; + constructor(bar) {} + } + } + constructor(foo, bar) {} + } + + B.m(); + expect(receivedLength).toBe(2); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-yield-private-super-property/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-yield-private-super-property/exec.js new file mode 100644 index 000000000000..4766b6546da4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-yield-private-super-property/exec.js @@ -0,0 +1,99 @@ +{ + let B; + + class CaptureFactory { + static *id(fn) { + yield fn; + } + } + + function dummy() {} + + class A extends CaptureFactory { + static #X = "A#X"; + static *[Symbol.iterator] () { + B = class B { + static #X = "B#X"; + @(yield* super.id(_ => _.#X), dummy) method () {} + @(yield* super.id(_ => _.#X), dummy) static method () {} + @(yield* super.id(_ => _.#X), dummy) get getter () {} + @(yield* super.id(_ => _.#X), dummy) static get getter () {} + @(yield* super.id(_ => _.#X), dummy) set setter (v) {} + @(yield* super.id(_ => _.#X), dummy) static set setter (v) {} + @(yield* super.id(_ => _.#X), dummy) property; + @(yield* super.id(_ => _.#X), dummy) static property; + @(yield* super.id(_ => _.#X), dummy) accessor accessor; + @(yield* super.id(_ => _.#X), dummy) static accessor accessor; + } + } + } + + expect([...A].map(fn => fn(B)).join(",")).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); +} + +{ + let B; + + class CaptureFactory { + static *id(fn) { + yield fn; + } + } + + function dummy() {} + + class A extends CaptureFactory { + static #X = "A#X"; + static *[Symbol.iterator] () { + B = @dummy + class B { + static #X = "B#X"; + @(yield* super.id(_ => _.#X), dummy) method () {} + @(yield* super.id(_ => _.#X), dummy) static method () {} + @(yield* super.id(_ => _.#X), dummy) get getter () {} + @(yield* super.id(_ => _.#X), dummy) static get getter () {} + @(yield* super.id(_ => _.#X), dummy) set setter (v) {} + @(yield* super.id(_ => _.#X), dummy) static set setter (v) {} + @(yield* super.id(_ => _.#X), dummy) property; + @(yield* super.id(_ => _.#X), dummy) static property; + @(yield* super.id(_ => _.#X), dummy) accessor accessor; + @(yield* super.id(_ => _.#X), dummy) static accessor accessor; + } + } + } + + expect([...A].map(fn => fn(B)).join(",")).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); +} + +{ + let B; + + class CaptureFactory { + static *id(fn) { + yield fn; + } + } + + function dummy() {} + + class A extends CaptureFactory { + static #X = "A#X"; + static *[Symbol.iterator] () { + B = class { + static #X = "B#X"; + @(yield* super.id(_ => _.#X), dummy) #method () {} + @(yield* super.id(_ => _.#X), dummy) static #Method () {} + @(yield* super.id(_ => _.#X), dummy) get #getter () {} + @(yield* super.id(_ => _.#X), dummy) static get #Getter () {} + @(yield* super.id(_ => _.#X), dummy) set #setter (v) {} + @(yield* super.id(_ => _.#X), dummy) static set #Setter (v) {} + @(yield* super.id(_ => _.#X), dummy) #property; + @(yield* super.id(_ => _.#X), dummy) static #Property; + @(yield* super.id(_ => _.#X), dummy) accessor #accessor; + @(yield* super.id(_ => _.#X), dummy) static accessor #Accessor; + } + } + } + + expect([...A].map(fn => fn(B)).join(",")).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-yield/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-yield/exec.js new file mode 100644 index 000000000000..28bfbb4bc84b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/decorator-evaluation-yield/exec.js @@ -0,0 +1,102 @@ +const noop = () => {}; +{ + const log = { + *[Symbol.iterator]() { + + class Foo { + @(yield 1, noop) method() {} + @(yield 2, noop) static method() {} + @(yield 3, noop) field; + @(yield 4, noop) static field; + @(yield 5, noop) get getter() { + return; + } + @(yield 6, noop) static get getter() { + return; + } + @(yield 7, noop) set setter(x) {} + @(yield 8, noop) static set setter(x) {} + @(yield 9, noop) accessor accessor; + @(yield 10, noop) static accessor accessor; + } + }, + }; + expect([...log].join()).toBe("1,2,3,4,5,6,7,8,9,10"); +} +{ + let Foo; + const log = { + *[Symbol.iterator]() { + + Foo = class { + @(yield 0, noop) [(yield 1, "method")]() {} + @(yield 2, noop) static method() {} + @(yield 3, noop) field; + @(yield 4, noop) static field; + @(yield 5, noop) get getter() { + return; + } + @(yield 6, noop) static get getter() { + return; + } + @(yield 7, noop) set setter(x) {} + @(yield 8, noop) static set setter(x) {} + @(yield 9, noop) accessor accessor; + @(yield 10, noop) static accessor accessor; + } + }, + }; + expect([...log].join()).toBe("0,1,2,3,4,5,6,7,8,9,10"); + expect((new Foo())).toHaveProperty("method"); +} +{ + const log = { + *[Symbol.iterator]() { + @(yield 0, noop) + class Foo { + @(yield 1, noop) method() {} + @(yield 2, noop) static method() {} + @(yield 3, noop) field; + @(yield 4, noop) static field; + @(yield 5, noop) get getter() { + return; + } + @(yield 6, noop) static get getter() { + return; + } + @(yield 7, noop) set setter(x) {} + @(yield 8, noop) static set setter(x) {} + @(yield 9, noop) accessor accessor; + @(yield 10, noop) static accessor accessor; + } + }, + }; + expect([...log].join()).toBe("0,1,2,3,4,5,6,7,8,9,10"); +} + +{ + let Foo; + const log = { + *[Symbol.iterator]() { + Foo = @(yield 0, noop) + class { + @(yield 1, noop) method() {} + @(yield 2, noop) static method() {} + @(yield 3, noop) field; + @(yield 4, noop) static field; + @(yield 5, noop) get getter() { + return; + } + @(yield 6, noop) static get getter() { + return; + } + @(yield 7, noop) set setter(x) {} + @(yield 8, noop) static set setter(x) {} + @(yield 9, noop) accessor accessor; + @(yield 10, noop) static accessor [(yield 11, "accessor")]; + } + }, + }; + expect([...log].join()).toBe("0,1,2,3,4,5,6,7,8,9,10,11"); + expect(Foo).toHaveProperty("accessor"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/destructuring-transform-integration/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/destructuring-transform-integration/input.js new file mode 100644 index 000000000000..7d71e215df9b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/destructuring-transform-integration/input.js @@ -0,0 +1,10 @@ +// from https://github.com/tc39/test262/blob/9e03c403e73341658d8d485a673798ae61f6f94a/test/language/statements/class/decorator/syntax/class-valid/decorator-member-expr-private-identifier.js +class C { + static #$() {} + static #_() {} + + static { + var D = @C.#$ + @C.#_ class {} + } +}; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/destructuring-transform-integration/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/destructuring-transform-integration/options.json new file mode 100644 index 000000000000..850578560357 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/destructuring-transform-integration/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block", + "transform-destructuring" + ], + "generatorOpts": { + "comments": false + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/destructuring-transform-integration/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/destructuring-transform-integration/output.js new file mode 100644 index 000000000000..3a95092c3bef --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/destructuring-transform-integration/output.js @@ -0,0 +1,7 @@ +class C {} +function _$() {} +function _() {} +((_initClass, _D, _D2, _babelHelpers$applyDe) => { + var D = (_D2 = class D {}, _babelHelpers$applyDe = babelHelpers.slicedToArray(babelHelpers.applyDecs2311(_D2, [_$, _], []).c, 2), _D = _babelHelpers$applyDe[0], _initClass = _babelHelpers$applyDe[1], _initClass(), _D); +})(); +; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initField-existing-derived-constructor/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initField-existing-derived-constructor/exec.js new file mode 100644 index 000000000000..ff55f12cd539 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initField-existing-derived-constructor/exec.js @@ -0,0 +1,175 @@ +{ + let self, a, initCalled; + + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + + class B { + constructor(s) { + a = s; + } + } + + class A extends B { + constructor() { + let a = 2; + self = super(a); + } + + @deco + accessor foo = 42; + } + + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} + +{ + const dec = ({ get, set }) => { + return { + get() { + return get.call(this) + 100; + }, + + set(v) { + set.call(this, v); + }, + } + }; + + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + + { + ("super() nested within another constructor should not be transformed"); + let log = []; + class A extends B { + constructor() { + log.push(super(3).method()); + new (class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("3,4"); + expect(a.foo).toBe(142); + } + + { + ("super() not in decorated derived constructor should not be transformed: computed key"); + let log = []; + new (class Dummy extends B { + constructor() { + let key; + class A extends B { + constructor() { + log.push(super(6).method()); + } + + @dec + accessor foo = 42; + + [((key = super(5).method()), log.push(key), key)]; + } + + const a = new A(); + + expect(a.foo).toBe(142); + } + })(); + + expect(log + "").toBe("5,6"); + } + + { + ("super() in decorator expression within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + new (class extends B { + constructor() { + class A extends B { + constructor() { + log.push(super(8).method()); + } + + @dec + accessor foo = 42; + + @noop(log.push(super(7).method())) noop() {} + } + + const a = new A(); + expect(a.foo).toBe(142); + } + })(); + + expect(log + "").toBe("7,8"); + } + + { + ("super() within decorated derived constructor should be transformed: computed key"); + let log = []; + class A extends B { + constructor() { + let key; + new (class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [((key = super(9).method()), log.push(key), key)]; + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("9,10"); + expect(a.foo).toBe(142); + } + + { + ("super() within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + class A extends B { + constructor() { + new (class Dummy extends B { + constructor() { + log.push(super(12).method()); + } + @noop(log.push(super(11).method())) noop() {} + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("11,12"); + expect(a.foo).toBe(142); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initField-existing-derived-constructor/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initField-existing-derived-constructor/input.js new file mode 100644 index 000000000000..ff55f12cd539 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initField-existing-derived-constructor/input.js @@ -0,0 +1,175 @@ +{ + let self, a, initCalled; + + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + + class B { + constructor(s) { + a = s; + } + } + + class A extends B { + constructor() { + let a = 2; + self = super(a); + } + + @deco + accessor foo = 42; + } + + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} + +{ + const dec = ({ get, set }) => { + return { + get() { + return get.call(this) + 100; + }, + + set(v) { + set.call(this, v); + }, + } + }; + + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + + { + ("super() nested within another constructor should not be transformed"); + let log = []; + class A extends B { + constructor() { + log.push(super(3).method()); + new (class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("3,4"); + expect(a.foo).toBe(142); + } + + { + ("super() not in decorated derived constructor should not be transformed: computed key"); + let log = []; + new (class Dummy extends B { + constructor() { + let key; + class A extends B { + constructor() { + log.push(super(6).method()); + } + + @dec + accessor foo = 42; + + [((key = super(5).method()), log.push(key), key)]; + } + + const a = new A(); + + expect(a.foo).toBe(142); + } + })(); + + expect(log + "").toBe("5,6"); + } + + { + ("super() in decorator expression within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + new (class extends B { + constructor() { + class A extends B { + constructor() { + log.push(super(8).method()); + } + + @dec + accessor foo = 42; + + @noop(log.push(super(7).method())) noop() {} + } + + const a = new A(); + expect(a.foo).toBe(142); + } + })(); + + expect(log + "").toBe("7,8"); + } + + { + ("super() within decorated derived constructor should be transformed: computed key"); + let log = []; + class A extends B { + constructor() { + let key; + new (class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [((key = super(9).method()), log.push(key), key)]; + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("9,10"); + expect(a.foo).toBe(142); + } + + { + ("super() within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + class A extends B { + constructor() { + new (class Dummy extends B { + constructor() { + log.push(super(12).method()); + } + @noop(log.push(super(11).method())) noop() {} + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("11,12"); + expect(a.foo).toBe(142); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initField-existing-derived-constructor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initField-existing-derived-constructor/output.js new file mode 100644 index 000000000000..b5f82d423ddc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initField-existing-derived-constructor/output.js @@ -0,0 +1,204 @@ +{ + var _A2; + let _init_foo, _init_extra_foo; + let self, a, initCalled; + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + class B { + constructor(s) { + a = s; + } + } + var _A = /*#__PURE__*/new WeakMap(); + class A extends B { + constructor() { + let a = 2; + self = (super(a), babelHelpers.classPrivateFieldInitSpec(this, _A, _init_foo(this, 42)), this, _init_extra_foo(this)); + } + get foo() { + return babelHelpers.classPrivateFieldGet2(_A, this); + } + set foo(v) { + babelHelpers.classPrivateFieldSet2(_A, this, v); + } + } + _A2 = A; + [_init_foo, _init_extra_foo] = babelHelpers.applyDecs2311(_A2, [], [[deco, 1, "foo"]], 0, void 0, B).e; + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} +{ + const dec = ({ + get, + set + }) => { + return { + get() { + return get.call(this) + 100; + }, + set(v) { + set.call(this, v); + } + }; + }; + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + { + var _A4; + let _init_foo2, _init_extra_foo2; + "super() nested within another constructor should not be transformed"; + let log = []; + var _A3 = /*#__PURE__*/new WeakMap(); + class A extends B { + constructor() { + log.push((super(3), babelHelpers.classPrivateFieldInitSpec(this, _A3, _init_foo2(this, 42)), this, _init_extra_foo2(this)).method()); + new class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + }(); + } + get foo() { + return babelHelpers.classPrivateFieldGet2(_A3, this); + } + set foo(v) { + babelHelpers.classPrivateFieldSet2(_A3, this, v); + } + } + _A4 = A; + [_init_foo2, _init_extra_foo2] = babelHelpers.applyDecs2311(_A4, [], [[dec, 1, "foo"]], 0, void 0, B).e; + const a = new A(); + expect(log + "").toBe("3,4"); + expect(a.foo).toBe(142); + } + { + "super() not in decorated derived constructor should not be transformed: computed key"; + let log = []; + new class Dummy extends B { + constructor() { + var _A6; + let _init_foo3, _init_extra_foo3, _computedKey; + let key; + var _A5 = /*#__PURE__*/new WeakMap(); + _computedKey = (key = super(5).method(), log.push(key), key); + class A extends B { + constructor() { + log.push((super(6), babelHelpers.classPrivateFieldInitSpec(this, _A5, _init_foo3(this, 42)), babelHelpers.defineProperty(this, _computedKey, void _init_extra_foo3(this))).method()); + } + get foo() { + return babelHelpers.classPrivateFieldGet2(_A5, this); + } + set foo(v) { + babelHelpers.classPrivateFieldSet2(_A5, this, v); + } + } + _A6 = A; + [_init_foo3, _init_extra_foo3] = babelHelpers.applyDecs2311(_A6, [], [[dec, 1, "foo"]], 0, void 0, B).e; + const a = new A(); + expect(a.foo).toBe(142); + } + }(); + expect(log + "").toBe("5,6"); + } + { + "super() in decorator expression within decorated derived constructor should be transformed: decorator expression"; + let log = []; + const noop = () => fn => fn; + new class extends B { + constructor() { + var _A8; + let _initProto, _init_foo4, _init_extra_foo4, _noopDecs, _ref; + var _A7 = /*#__PURE__*/new WeakMap(); + _ref = (_noopDecs = noop(log.push(super(7).method())), "foo"); + class A extends B { + constructor() { + log.push((super(8), babelHelpers.classPrivateFieldInitSpec(this, _A7, (_initProto(this), _init_foo4(this, 42))), this, _init_extra_foo4(this)).method()); + } + get [_ref]() { + return babelHelpers.classPrivateFieldGet2(_A7, this); + } + set foo(v) { + babelHelpers.classPrivateFieldSet2(_A7, this, v); + } + noop() {} + } + _A8 = A; + [_init_foo4, _init_extra_foo4, _initProto] = babelHelpers.applyDecs2311(_A8, [], [[dec, 1, "foo"], [_noopDecs, 2, "noop"]], 0, void 0, B).e; + const a = new A(); + expect(a.foo).toBe(142); + } + }(); + expect(log + "").toBe("7,8"); + } + { + var _A10; + let _init_foo5, _init_extra_foo5; + "super() within decorated derived constructor should be transformed: computed key"; + let log = []; + var _A9 = /*#__PURE__*/new WeakMap(); + class A extends B { + constructor() { + let _ref2; + let key; + new (_ref2 = (key = (super(9), babelHelpers.classPrivateFieldInitSpec(this, _A9, _init_foo5(this, 42)), this, _init_extra_foo5(this)).method(), log.push(key), key), class Dummy extends B { + constructor() { + log.push((super(10), babelHelpers.defineProperty(this, _ref2, void 0)).method()); + } + })(); + } + get foo() { + return babelHelpers.classPrivateFieldGet2(_A9, this); + } + set foo(v) { + babelHelpers.classPrivateFieldSet2(_A9, this, v); + } + } + _A10 = A; + [_init_foo5, _init_extra_foo5] = babelHelpers.applyDecs2311(_A10, [], [[dec, 1, "foo"]], 0, void 0, B).e; + const a = new A(); + expect(log + "").toBe("9,10"); + expect(a.foo).toBe(142); + } + { + var _A12; + let _init_foo6, _init_extra_foo6; + "super() within decorated derived constructor should be transformed: decorator expression"; + let log = []; + const noop = () => fn => fn; + var _A11 = /*#__PURE__*/new WeakMap(); + class A extends B { + constructor() { + var _Dummy2; + let _initProto2, _noopDecs2, _ref3; + new (_ref3 = (_noopDecs2 = noop(log.push((super(11), babelHelpers.classPrivateFieldInitSpec(this, _A11, _init_foo6(this, 42)), this, _init_extra_foo6(this)).method())), "noop"), _Dummy2 = class Dummy extends B { + constructor() { + log.push(_initProto2(super(12)).method()); + } + [_ref3]() {} + }, [_initProto2] = babelHelpers.applyDecs2311(_Dummy2, [], [[_noopDecs2, 2, "noop"]], 0, void 0, B).e, _Dummy2)(); + } + get foo() { + return babelHelpers.classPrivateFieldGet2(_A11, this); + } + set foo(v) { + babelHelpers.classPrivateFieldSet2(_A11, this, v); + } + } + _A12 = A; + [_init_foo6, _init_extra_foo6] = babelHelpers.applyDecs2311(_A12, [], [[dec, 1, "foo"]], 0, void 0, B).e; + const a = new A(); + expect(log + "").toBe("11,12"); + expect(a.foo).toBe(142); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initProto-existing-derived-constructor/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initProto-existing-derived-constructor/exec.js new file mode 100644 index 000000000000..4edba29a60bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initProto-existing-derived-constructor/exec.js @@ -0,0 +1,173 @@ +{ + let self, a, initCalled; + + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + + class B { + constructor(s) { + a = s; + } + } + + class A extends B { + constructor() { + let a = 2; + self = super(a); + } + + @deco + method() {} + } + + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} + +{ + const dec = (fn) => { + return function () { + return fn.call(this) + 100; + }; + }; + + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + + { + ("super() nested within another constructor should not be transformed"); + let log = []; + class A extends B { + constructor() { + log.push(super(3).method()); + new (class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("103,4"); + } + + { + ("super() not in decorated derived constructor should not be transformed: computed key"); + let log = []; + new (class Dummy extends B { + constructor() { + let key; + class A extends B { + constructor() { + log.push(super(6).method()); + } + + @dec + method() { + return this.a; + } + + [((key = super(5).method()), log.push(key), key)]; + } + + new A(); + } + })(); + + expect(log + "").toBe("5,106"); + } + + { + ("super() in decorator expression within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + new (class extends B { + constructor() { + class A extends B { + constructor() { + log.push(super(8).method()); + } + + @dec + method() { + return this.a; + } + + @noop(log.push(super(7).method())) noop() {} + } + + new A(); + } + })(); + + expect(log + "").toBe("7,108"); + } + + { + ("super() within decorated derived constructor should be transformed: computed key"); + let log = []; + class A extends B { + constructor() { + let key; + new (class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [((key = super(9).method()), log.push(key), key)]; + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("109,10"); + } + + { + ("super() within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + class A extends B { + constructor() { + new (class Dummy extends B { + constructor() { + log.push(super(12).method()); + } + @noop(log.push(super(11).method())) noop() {} + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("111,12"); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initProto-existing-derived-constructor/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initProto-existing-derived-constructor/input.js new file mode 100644 index 000000000000..4edba29a60bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initProto-existing-derived-constructor/input.js @@ -0,0 +1,173 @@ +{ + let self, a, initCalled; + + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + + class B { + constructor(s) { + a = s; + } + } + + class A extends B { + constructor() { + let a = 2; + self = super(a); + } + + @deco + method() {} + } + + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} + +{ + const dec = (fn) => { + return function () { + return fn.call(this) + 100; + }; + }; + + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + + { + ("super() nested within another constructor should not be transformed"); + let log = []; + class A extends B { + constructor() { + log.push(super(3).method()); + new (class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("103,4"); + } + + { + ("super() not in decorated derived constructor should not be transformed: computed key"); + let log = []; + new (class Dummy extends B { + constructor() { + let key; + class A extends B { + constructor() { + log.push(super(6).method()); + } + + @dec + method() { + return this.a; + } + + [((key = super(5).method()), log.push(key), key)]; + } + + new A(); + } + })(); + + expect(log + "").toBe("5,106"); + } + + { + ("super() in decorator expression within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + new (class extends B { + constructor() { + class A extends B { + constructor() { + log.push(super(8).method()); + } + + @dec + method() { + return this.a; + } + + @noop(log.push(super(7).method())) noop() {} + } + + new A(); + } + })(); + + expect(log + "").toBe("7,108"); + } + + { + ("super() within decorated derived constructor should be transformed: computed key"); + let log = []; + class A extends B { + constructor() { + let key; + new (class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [((key = super(9).method()), log.push(key), key)]; + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("109,10"); + } + + { + ("super() within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + class A extends B { + constructor() { + new (class Dummy extends B { + constructor() { + log.push(super(12).method()); + } + @noop(log.push(super(11).method())) noop() {} + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("111,12"); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initProto-existing-derived-constructor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initProto-existing-derived-constructor/output.js new file mode 100644 index 000000000000..5ff9ad6b9252 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initProto-existing-derived-constructor/output.js @@ -0,0 +1,165 @@ +{ + var _A; + let _initProto; + let self, a, initCalled; + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + class B { + constructor(s) { + a = s; + } + } + class A extends B { + constructor() { + let a = 2; + self = _initProto(super(a)); + } + method() {} + } + _A = A; + [_initProto] = babelHelpers.applyDecs2311(_A, [], [[deco, 2, "method"]], 0, void 0, B).e; + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} +{ + const dec = fn => { + return function () { + return fn.call(this) + 100; + }; + }; + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + { + var _A2; + let _initProto2; + "super() nested within another constructor should not be transformed"; + let log = []; + class A extends B { + constructor() { + log.push(_initProto2(super(3)).method()); + new class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + }(); + } + method() { + return this.a; + } + } + _A2 = A; + [_initProto2] = babelHelpers.applyDecs2311(_A2, [], [[dec, 2, "method"]], 0, void 0, B).e; + new A(); + expect(log + "").toBe("103,4"); + } + { + "super() not in decorated derived constructor should not be transformed: computed key"; + let log = []; + new class Dummy extends B { + constructor() { + var _A3; + let _initProto3, _computedKey; + let key; + _computedKey = (key = super(5).method(), log.push(key), key); + class A extends B { + constructor() { + log.push((super(6), babelHelpers.defineProperty(this, _computedKey, void _initProto3(this))).method()); + } + method() { + return this.a; + } + } + _A3 = A; + [_initProto3] = babelHelpers.applyDecs2311(_A3, [], [[dec, 2, "method"]], 0, void 0, B).e; + new A(); + } + }(); + expect(log + "").toBe("5,106"); + } + { + "super() in decorator expression within decorated derived constructor should be transformed: decorator expression"; + let log = []; + const noop = () => fn => fn; + new class extends B { + constructor() { + var _A4; + let _initProto4, _noopDecs, _ref; + _ref = (_noopDecs = noop(log.push(super(7).method())), "method"); + class A extends B { + constructor() { + log.push(_initProto4(super(8)).method()); + } + [_ref]() { + return this.a; + } + noop() {} + } + _A4 = A; + [_initProto4] = babelHelpers.applyDecs2311(_A4, [], [[dec, 2, "method"], [_noopDecs, 2, "noop"]], 0, void 0, B).e; + new A(); + } + }(); + expect(log + "").toBe("7,108"); + } + { + var _A5; + let _initProto5; + "super() within decorated derived constructor should be transformed: computed key"; + let log = []; + class A extends B { + constructor() { + let _ref2; + let key; + new (_ref2 = (key = _initProto5(super(9)).method(), log.push(key), key), class Dummy extends B { + constructor() { + log.push((super(10), babelHelpers.defineProperty(this, _ref2, void 0)).method()); + } + })(); + } + method() { + return this.a; + } + } + _A5 = A; + [_initProto5] = babelHelpers.applyDecs2311(_A5, [], [[dec, 2, "method"]], 0, void 0, B).e; + new A(); + expect(log + "").toBe("109,10"); + } + { + var _A6; + let _initProto6; + "super() within decorated derived constructor should be transformed: decorator expression"; + let log = []; + const noop = () => fn => fn; + class A extends B { + constructor() { + var _Dummy2; + let _initProto7, _noopDecs2, _ref3; + new (_ref3 = (_noopDecs2 = noop(log.push(_initProto6(super(11)).method())), "noop"), _Dummy2 = class Dummy extends B { + constructor() { + log.push(_initProto7(super(12)).method()); + } + [_ref3]() {} + }, [_initProto7] = babelHelpers.applyDecs2311(_Dummy2, [], [[_noopDecs2, 2, "noop"]], 0, void 0, B).e, _Dummy2)(); + } + method() { + return this.a; + } + } + _A6 = A; + [_initProto6] = babelHelpers.applyDecs2311(_A6, [], [[dec, 2, "method"]], 0, void 0, B).e; + new A(); + expect(log + "").toBe("111,12"); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initializer-property-ignored/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initializer-property-ignored/exec.js new file mode 100644 index 000000000000..2828e1c22408 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initializer-property-ignored/exec.js @@ -0,0 +1,25 @@ +let init = false; +let initializer = false; + +function decorator() { + return { + get init() { + init = true; + return () => {}; + }, + get initializer() { + initializer = true; + return () => {}; + } + }; +} + +class A { + @decorator + accessor x; +} + +new A(); + +expect(init).toBe(true); +expect(initializer).toBe(false); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initializer-timing/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initializer-timing/exec.js new file mode 100644 index 000000000000..ac5920dcd16a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/initializer-timing/exec.js @@ -0,0 +1,34 @@ +function dec1(fn, context) { + context.addInitializer((instance) => { + expect(instance.value).toBe(undefined); + }); + + return fn; +} + +class Foo { + value = 1; + + @dec1 + foo() {} +} + +function dec2(fn, context) { + context.addInitializer((instance) => { + expect(instance.value).toBe(1); + }); + + return fn; +} + + +class Bar extends Foo { + constructor() { + super(); + + this.value = 2; + } + + @dec2 + bar() {} +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/invalid-non-callable-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/invalid-non-callable-decorators/exec.js new file mode 100644 index 000000000000..9249424de280 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/invalid-non-callable-decorators/exec.js @@ -0,0 +1,43 @@ +{ + "invalid non-callable class decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => @nonCallable class {}).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable field decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable field }).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable accessor decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable accessor accessor; }).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable method decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable method() {} }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined class decorators"; + expect(() => @(void 0) class {}).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined field decorators"; + expect(() => class { @(void 0) field }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined accessor decorators"; + expect(() => class { @(void 0) accessor accessor; }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined method decorators"; + expect(() => class { @(void 0) method() {} }).toThrow("A decorator must be a function"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/leaked-context-addInitializer-throw-2/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/leaked-context-addInitializer-throw-2/exec.js new file mode 100644 index 000000000000..42088724214e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/leaked-context-addInitializer-throw-2/exec.js @@ -0,0 +1,20 @@ +let addInitializer; + +function decMethod(_, context) { + ({ addInitializer } = context); + return null; +} + +try { + class C { + @decMethod + m() {} + } +} catch(_) {} + +const testFn = () => { + addInitializer(() => null); +}; + +expect(testFn).toThrow(TypeError); +expect(testFn).toThrow('attempted to call addInitializer after decoration was finished'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/leaked-context-addInitializer-throw/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/leaked-context-addInitializer-throw/exec.js new file mode 100644 index 000000000000..8dac832a8c97 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/leaked-context-addInitializer-throw/exec.js @@ -0,0 +1,17 @@ +let addInitializer; + +function decMethod(_, context) { + ({ addInitializer } = context); + throw new Error(); +} + +try { + class C { + @decMethod + m() {} + } +} catch(_) {} + +expect(() => { + addInitializer(() => null); +}).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/leaked-context-addInitializer/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/leaked-context-addInitializer/exec.js new file mode 100644 index 000000000000..ff406600f057 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/leaked-context-addInitializer/exec.js @@ -0,0 +1,21 @@ +let addInitializer; + +function callCapturedFunc() { + addInitializer(() => null); +} + +function decMethod(_, context) { + ({ addInitializer } = context); + addInitializer(() => null); +} + +const testFn = () => { + class C { + @callCapturedFunc + @decMethod + m() {} + } +}; + +expect(testFn).toThrow(TypeError); +expect(testFn).toThrow('attempted to call addInitializer after decoration was finished') diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/exec.js new file mode 100644 index 000000000000..3a82579f1c64 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/exec.js @@ -0,0 +1,153 @@ +{ + "class binding in plain class, decorated field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + capture(() => K); + assertUninitialized(() => K); + + class K { + @capture(() => K) @assertUninitialized(() => K) [(capture(() => K), assertUninitialized(() => K))] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E, E, E]); + + const C = K; + // expect(fns.map(fn => fn())).toEqual([C, C, C]); + // todo: remove these three and enable the assertions above when we properly handle class tdz + expect(fns[0]()).toEqual(C); + expect(fns[1]).toThrow(E); + expect(fns[2]).toThrow(E); + + K = null; + + // expect(fns.map(fn => fn())).toEqual([null, C, C]); + // todo: remove these three and enable the assertions above when we properly handle class tdz + expect(fns[0]()).toEqual(null); + expect(fns[1]).toThrow(E); + expect(fns[2]).toThrow(E); +} + +{ + "class binding in decorated class, decorated field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(() => K) + @assertUninitialized(() => K) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(() => K) [capture(() => K)] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + [K = null] = []; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated static field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(() => K) + @assertUninitialized(() => K) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(() => K) static [capture(() => K)] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + ({ K = null } = {}); + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated static method, and computed keys with await"; + (async () => { + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(await (() => K)) + @assertUninitialized(await (() => K)) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(await (() => K)) static [capture(await (() => K))]() {} + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + [K] = [null]; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); + })() +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/input.js new file mode 100644 index 000000000000..3a82579f1c64 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/input.js @@ -0,0 +1,153 @@ +{ + "class binding in plain class, decorated field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + capture(() => K); + assertUninitialized(() => K); + + class K { + @capture(() => K) @assertUninitialized(() => K) [(capture(() => K), assertUninitialized(() => K))] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E, E, E]); + + const C = K; + // expect(fns.map(fn => fn())).toEqual([C, C, C]); + // todo: remove these three and enable the assertions above when we properly handle class tdz + expect(fns[0]()).toEqual(C); + expect(fns[1]).toThrow(E); + expect(fns[2]).toThrow(E); + + K = null; + + // expect(fns.map(fn => fn())).toEqual([null, C, C]); + // todo: remove these three and enable the assertions above when we properly handle class tdz + expect(fns[0]()).toEqual(null); + expect(fns[1]).toThrow(E); + expect(fns[2]).toThrow(E); +} + +{ + "class binding in decorated class, decorated field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(() => K) + @assertUninitialized(() => K) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(() => K) [capture(() => K)] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + [K = null] = []; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated static field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(() => K) + @assertUninitialized(() => K) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(() => K) static [capture(() => K)] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + ({ K = null } = {}); + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated static method, and computed keys with await"; + (async () => { + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(await (() => K)) + @assertUninitialized(await (() => K)) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(await (() => K)) static [capture(await (() => K))]() {} + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + [K] = [null]; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); + })() +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/options.json new file mode 100644 index 000000000000..6386e25ffdf6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "7.6.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/output.js new file mode 100644 index 000000000000..f5d16e686eb6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/outer-class-binding-mutated/output.js @@ -0,0 +1,192 @@ +{ + var _K; + let _computedKeyDecs, _computedKey, _init_computedKey, _init_extra_computedKey, _ref; + "class binding in plain class, decorated field, and computed keys"; + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {}; + }; + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {}; + } + }; + capture(() => K); + assertUninitialized(() => K); + _ref = (_computedKeyDecs = [capture(() => (babelHelpers.classNameTDZError("K"), K)), assertUninitialized(() => (babelHelpers.classNameTDZError("K"), K))], _computedKey = babelHelpers.toPropertyKey((capture(() => (babelHelpers.classNameTDZError("K"), K)), assertUninitialized(() => (babelHelpers.classNameTDZError("K"), K))))); + class K { + constructor() { + babelHelpers.defineProperty(this, _ref, _init_computedKey(this)); + _init_extra_computedKey(this); + } + } + _K = K; + [_init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(_K, [], [[_computedKeyDecs, 0, _computedKey]]).e; + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E, E, E]); + const C = K; + // expect(fns.map(fn => fn())).toEqual([C, C, C]); + // todo: remove these three and enable the assertions above when we properly handle class tdz + expect(fns[0]()).toEqual(C); + expect(fns[1]).toThrow(E); + expect(fns[2]).toThrow(E); + K = null; + + // expect(fns.map(fn => fn())).toEqual([null, C, C]); + // todo: remove these three and enable the assertions above when we properly handle class tdz + expect(fns[0]()).toEqual(null); + expect(fns[1]).toThrow(E); + expect(fns[2]).toThrow(E); +} +{ + let _initClass, _classDecs, _computedKeyDecs2, _computedKey2, _init_computedKey2, _init_extra_computedKey2; + "class binding in decorated class, decorated field, and computed keys"; + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {}; + }; + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {}; + } + }; + _classDecs = [capture(() => _K2), assertUninitialized(() => _K2)]; + let _K2, _t_K; + { + var _K3; + let _ref2; + let _K2; + _ref2 = (_computedKeyDecs2 = capture(() => _K2), _computedKey2 = babelHelpers.toPropertyKey(capture(() => _K2))); + class K { + constructor() { + //todo: add the assertUninitialized decorator when we properly implement class tdz + babelHelpers.defineProperty(this, _ref2, _init_computedKey2(this)); + _init_extra_computedKey2(this); + } + } + _K3 = K; + ({ + e: [_init_computedKey2, _init_extra_computedKey2], + c: [_K2, _initClass] + } = babelHelpers.applyDecs2311(_K3, _classDecs, [[_computedKeyDecs2, 0, _computedKey2]])); + _initClass(); + _t_K = _K2; + } + _K2 = _t_K; + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + const C = _K2; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + [_K2 = null] = []; + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} +{ + let _initClass2, _classDecs2, _computedKeyDecs3, _computedKey3, _init_computedKey3, _init_extra_computedKey3; + "class binding in decorated class, decorated static field, and computed keys"; + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {}; + }; + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {}; + } + }; + _classDecs2 = [capture(() => _K4), assertUninitialized(() => _K4)]; + let _K4, _t_K2; + { + var _Class, _K6; + let _K5, _ref3; + let _K4; + new (_K5 = (_ref3 = (_computedKeyDecs3 = capture(() => _K4), _computedKey3 = babelHelpers.toPropertyKey(capture(() => _K4)), "_"), _K6 = class K {}, babelHelpers.defineProperty(_K6, _ref3, void 0), (() => { + delete _K6._; + ({ + e: [_init_computedKey3, _init_extra_computedKey3], + c: [_K4, _initClass2] + } = babelHelpers.applyDecs2311(_K6, _classDecs2, [[_computedKeyDecs3, 8, _computedKey3]])); + })(), _K6), _Class = class extends babelHelpers.identity { + constructor() { + super(_K4), babelHelpers.defineProperty(this, _computedKey3, _init_computedKey3()), (() => { + _init_extra_computedKey3(); + })(), _initClass2(); + } + }, babelHelpers.defineProperty(_Class, _K5, void 0), _Class)(); + _t_K2 = _K4; + } + _K4 = _t_K2; + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + const C = _K4; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + ({ + K: _K4 = null + } = {}); + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} +{ + "class binding in decorated class, decorated static method, and computed keys with await"; + (async (_initStatic, _initClass3, _classDecs3, _computedKeyDecs4, _computedKey5) => { + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {}; + }; + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {}; + } + }; + _classDecs3 = [capture(await (() => _K7)), assertUninitialized(await (() => _K7))]; + let _K7, _t_K3; + { + var _K8; + let _ref4; + let _K7; + _ref4 = (_computedKeyDecs4 = capture(await (() => _K7)), _computedKey5 = babelHelpers.toPropertyKey(capture(await (() => _K7)))); + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + static [_ref4]() {} + } + _K8 = K; + (() => { + ({ + e: [_initStatic], + c: [_K7, _initClass3] + } = babelHelpers.applyDecs2311(_K8, _classDecs3, [[_computedKeyDecs4, 10, _computedKey5]])); + _initStatic(_K8); + })(); + _initClass3(); + _t_K3 = _K7; + } + _K7 = _t_K3; + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + const C = _K7; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + [_K7] = [null]; + expect(fns.map(fn => fn())).toEqual([null, C, C]); + })(); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/private-name-in-class-decorator/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/private-name-in-class-decorator/exec.js new file mode 100644 index 000000000000..f37dda0b1d8c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/private-name-in-class-decorator/exec.js @@ -0,0 +1,14 @@ +let called = false; + +class A { + static #x() { called = true } + constructor() { + @(A.#x) + class B extends A { + static #x() { throw new Error("Should not be called") } + } + } +} + +new A(); +expect(called).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/private-name-in-class-decorator/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/private-name-in-class-decorator/input.js new file mode 100644 index 000000000000..f37dda0b1d8c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/private-name-in-class-decorator/input.js @@ -0,0 +1,14 @@ +let called = false; + +class A { + static #x() { called = true } + constructor() { + @(A.#x) + class B extends A { + static #x() { throw new Error("Should not be called") } + } + } +} + +new A(); +expect(called).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/private-name-in-class-decorator/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/private-name-in-class-decorator/output.js new file mode 100644 index 000000000000..65fd79734127 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/private-name-in-class-decorator/output.js @@ -0,0 +1,21 @@ +let called = false; +class A { + constructor() { + var _Class, _Class_brand, _B3; + let _initClass, _B2; + let _B; + new (_Class_brand = /*#__PURE__*/new WeakSet(), _B2 = (_B3 = class B extends A {}, [_B, _initClass] = babelHelpers.applyDecs2311(_B3, [_x], [], 0, void 0, A).c, _B3), _Class = class extends babelHelpers.identity { + constructor() { + super(_B), babelHelpers.classPrivateMethodInitSpec(this, _Class_brand), this, _initClass(); + } + }, babelHelpers.defineProperty(_Class, _B2, void 0), _Class)(); + function _x3() { + throw new Error("Should not be called"); + } + } +} +function _x() { + called = true; +} +new A(); +expect(called).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/super-in-decorator/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/super-in-decorator/input.js new file mode 100644 index 000000000000..7e75b7766176 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/super-in-decorator/input.js @@ -0,0 +1,9 @@ +class A extends B { + m() { + @(super.dec1) + class C { + @(super.dec2) + m2() {} + } + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/super-in-decorator/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/super-in-decorator/output.js new file mode 100644 index 000000000000..7ace50caf2ba --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/super-in-decorator/output.js @@ -0,0 +1,21 @@ +class A extends B { + m() { + var _C2; + let _initProto, _initClass, _classDecs, _m2Decs, _ref; + _classDecs = [this, super.dec1]; + let _C; + _ref = (_m2Decs = [this, super.dec2], "m2"); + class C { + constructor() { + _initProto(this); + } + [_ref]() {} + } + _C2 = C; + ({ + e: [_initProto], + c: [_C, _initClass] + } = babelHelpers.applyDecs2311(_C2, _classDecs, [[_m2Decs, 18, "m2"]], 1)); + _initClass(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/this/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/this/exec.js new file mode 100644 index 000000000000..e418f72569e9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/this/exec.js @@ -0,0 +1,26 @@ +"use strict"; + +let _this = []; + +function dec() { + _this.push(this); +} + +let o1 = { dec }; +let o2 = { dec }; +let o3 = { o: { dec } }; + +@o1.dec +@dec +@o2.dec +class A { + @o2.dec + @o3.o.dec + x; + + @o2.dec + @dec + y; +} + +expect(_this).toEqual([o3.o, o2, undefined, o2, o2, undefined, o1]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/this/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/this/input.js new file mode 100644 index 000000000000..c95350691ddb --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/this/input.js @@ -0,0 +1,12 @@ +@o1.dec +@dec +@o2.dec +class A { + @o2.dec + @o3.o.dec + x; + + @o2.dec + @dec + y; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/this/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/this/output.js new file mode 100644 index 000000000000..ae7ca6c7d665 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/this/output.js @@ -0,0 +1,16 @@ +var _A2; +let _initClass, _obj, _init_x, _init_extra_x, _init_y, _init_extra_y; +let _A; +class A { + constructor() { + babelHelpers.defineProperty(this, "x", _init_x(this)); + babelHelpers.defineProperty(this, "y", (_init_extra_x(this), _init_y(this))); + _init_extra_y(this); + } +} +_A2 = A; +({ + e: [_init_x, _init_extra_x, _init_y, _init_extra_y], + c: [_A, _initClass] +} = babelHelpers.applyDecs2311(_A2, [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec], [[[_obj = o2, _obj.dec, _obj = o3.o, _obj.dec], 16, "x"], [[_obj = o2, _obj.dec, void 0, dec], 16, "y"]], 1)); +_initClass(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/valid-expression-formats/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/valid-expression-formats/input.js new file mode 100644 index 000000000000..586564c5e219 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/valid-expression-formats/input.js @@ -0,0 +1,23 @@ +const dec = () => {}; +@dec +@call() +@chain.expr() +@(arbitrary + expr) +@(array[expr]) +class Foo { + #a; + + @dec + @call() + @chain.expr() + @(arbitrary + expr) + @(array[expr]) + method() {} + + makeClass() { + return class Nested { + @(this.#a) + bar; + } + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/valid-expression-formats/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/valid-expression-formats/output.js new file mode 100644 index 000000000000..40191d71182c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc--to-es2015/valid-expression-formats/output.js @@ -0,0 +1,27 @@ +var _Foo2; +let _initProto, _initClass, _obj; +const dec = () => {}; +let _Foo; +var _a = /*#__PURE__*/new WeakMap(); +class Foo { + constructor() { + babelHelpers.classPrivateFieldInitSpec(this, _a, void _initProto(this)); + } + method() {} + makeClass() { + var _Nested; + let _barDecs, _init_bar, _init_extra_bar, _ref; + return _ref = (_barDecs = babelHelpers.classPrivateFieldGet2(_a, this), "bar"), _Nested = class Nested { + constructor() { + babelHelpers.defineProperty(this, _ref, _init_bar(this)); + _init_extra_bar(this); + } + }, [_init_bar, _init_extra_bar] = babelHelpers.applyDecs2311(_Nested, [], [[_barDecs, 0, "bar"]]).e, _Nested; + } +} +_Foo2 = Foo; +({ + e: [_initProto], + c: [_Foo, _initClass] +} = babelHelpers.applyDecs2311(_Foo2, [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]], [[[void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]], 18, "method"]], 1)); +_initClass(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/all-decorators/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/all-decorators/input.js new file mode 100644 index 000000000000..6986908e606d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/all-decorators/input.js @@ -0,0 +1,27 @@ +const dec = () => {}; +@dec +class Class { + @dec a; + @dec b() {} + @dec get c() {} + @dec set c(v) {} + @dec accessor d; + + @dec #e; + @dec #f() {} + @dec get #g() {} + @dec set #g(v) {} + @dec accessor #h; + + @dec static i; + @dec static j() {} + @dec static get k() {} + @dec static set l(v) {} + @dec static accessor m; + + @dec static #n; + @dec static #o() {} + @dec static get #p() {} + @dec static set #q(v) {} + @dec static accessor #r; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/all-decorators/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/all-decorators/output.js new file mode 100644 index 000000000000..3bb776b4b815 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/all-decorators/output.js @@ -0,0 +1,74 @@ +let _initProto, _initStatic, _initClass, _init_a, _init_extra_a, _init_d, _init_extra_d, _init_e, _init_extra_e, _call_f, _call_g, _call_g2, _init_h, _get_h, _set_h, _init_extra_h, _init_i, _init_extra_i, _init_m, _init_extra_m, _init_n, _init_extra_n, _call_o, _call_p, _call_q, _init_r, _get_r, _set_r, _init_extra_r; +const dec = () => {}; +let _Class; +new class extends babelHelpers.identity { + static [class Class { + static { + ({ + e: [_init_m, _init_extra_m, _call_o, _call_p, _call_q, _init_r, _get_r, _set_r, _init_extra_r, _init_d, _init_extra_d, _call_f, _call_g, _call_g2, _init_h, _get_h, _set_h, _init_extra_h, _init_i, _init_extra_i, _init_n, _init_extra_n, _init_a, _init_extra_a, _init_e, _init_extra_e, _initProto, _initStatic], + c: [_Class, _initClass] + } = babelHelpers.applyDecs2311(this, [dec], [[dec, 0, "a"], [dec, 2, "b"], [dec, 3, "c"], [dec, 4, "c"], [dec, 1, "d"], [dec, 0, "e", o => o.#e, (o, v) => o.#e = v], [dec, 2, "f", function () {}], [dec, 3, "g", function () {}], [dec, 4, "g", function (v) {}], [dec, 1, "h", o => o.#B, (o, v) => o.#B = v], [dec, 8, "i"], [dec, 10, "j"], [dec, 11, "k"], [dec, 12, "l"], [dec, 9, "m"], [dec, 8, "n", o => o.#n, (o, v) => o.#n = v], [dec, 10, "o", function () {}], [dec, 11, "p", function () {}], [dec, 12, "q", function (v) {}], [dec, 9, "r", o => o.#D, (o, v) => o.#D = v]], 0, _ => #e in _)); + _initStatic(this); + } + constructor() { + _init_extra_h(this); + } + #f = _call_f; + a = (_initProto(this), _init_a(this)); + b() {} + get c() {} + set c(v) {} + #A = (_init_extra_a(this), _init_d(this)); + get d() { + return this.#A; + } + set d(v) { + this.#A = v; + } + #e = (_init_extra_d(this), _init_e(this)); + get #g() { + return _call_g(this); + } + set #g(v) { + _call_g2(this, v); + } + #B = (_init_extra_e(this), _init_h(this)); + set #h(v) { + _set_h(this, v); + } + get #h() { + return _get_h(this); + } + static j() {} + static get k() {} + static set l(v) {} + static get m() { + return Class.#C; + } + static set m(v) { + Class.#C = v; + } + }]; + #o = _call_o; + i = _init_i(); + #C = (_init_extra_i(), _init_m()); + #n = (_init_extra_m(), _init_n()); + get #p() { + return _call_p(this); + } + set #q(v) { + _call_q(this, v); + } + #D = (_init_extra_n(), _init_r()); + set #r(v) { + _set_r(v); + } + get #r() { + return _get_r(); + } + constructor() { + super(_Class), (() => { + _init_extra_r(); + })(), _initClass(); + } +}(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-in-for-loop/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-in-for-loop/exec.js new file mode 100644 index 000000000000..1074cab15fb5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-in-for-loop/exec.js @@ -0,0 +1,94 @@ +{ + const logs = []; + const classes = []; + const noop = () => {} + + for (let i = 0; i < 2; i++) { + classes.push(class C { + @noop [i]; + }) + } + + for (const clazz of classes) { + logs.push(Reflect.ownKeys(new clazz())); + } + + expect(logs.join()).toBe("0,1"); +} + +{ + const logs = []; + const classes = []; + const noop = () => {} + + for (let i = 0; i < 2; i++) { + classes.push(@noop class C { + [i]; + }) + } + + for (const clazz of classes) { + logs.push(Reflect.ownKeys(new clazz())); + } + + expect(logs.join()).toBe("0,1"); +} + +{ + const logs = []; + const classes = []; + const noop = () => {} + + for (let i = 0; i < 2; i++) { + classes.push(@noop class C { + @noop [i]; + }) + } + + for (const clazz of classes) { + logs.push(Reflect.ownKeys(new clazz())); + } + + expect(logs.join()).toBe("0,1"); +} + +{ + const logs = []; + const classes = []; + const setValueTo = i => () => () => i + + for (let i = 0; i < 2; i++) { + classes.push(class C { + @setValueTo(i) [i]; + }) + } + + for (const clazz of classes) { + const c = new clazz(); + const key = Reflect.ownKeys(c)[0]; + logs.push([key, c[key]].join(":")); + } + + expect(logs.join()).toBe("0:0,1:1"); +} + +{ + const logs = []; + const classes = []; + const noop = () => {} + const setValueTo = i => (_, { access, addInitializer }) => addInitializer(function() { access.set(this, i) }) + + for (let i = 0; i < 2; i++) { + classes.push(@noop class C { + @setValueTo(i) [i]; + }) + } + + for (const clazz of classes) { + const c = new clazz(); + const key = Reflect.ownKeys(c)[0]; + logs.push([key, c[key]].join(":")); + } + + expect(logs.join()).toBe("0:0,1:1"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-not-available-during-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-not-available-during-decorators/exec.js new file mode 100644 index 000000000000..c3885caa4ec8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-not-available-during-decorators/exec.js @@ -0,0 +1,14 @@ +let didRun = false; + +function dec(fn) { + fn(); + return () => {}; +} + +@dec(() => { + expect(() => Foo.x).toThrow(); + didRun = true; +}) class Foo {} + +expect(didRun).toBe(true); + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-not-available-during-decorators/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-not-available-during-decorators/options.json new file mode 100644 index 000000000000..6c1e089b4472 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-not-available-during-decorators/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "12.0.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-underscore-property/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-underscore-property/exec.js new file mode 100644 index 000000000000..bc28d94fb7b4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/class-underscore-property/exec.js @@ -0,0 +1,52 @@ +function noopFactory() { return function noop() {} } + +{ + class B { + @noopFactory() + static _ = "B"; + } + + class C extends B { + @noopFactory() #p; + } + + expect(C._).toBe("B"); +} + +{ + class B { + @noopFactory() + static _ = "B"; + } + + @noopFactory() + class C extends B { + @noopFactory() #p; + } + + expect(C._).toBe("B"); +} + +{ + class C { + @noopFactory() #p; + } + + expect(Reflect.ownKeys(C)).not.toContain("_"); +} + +{ + @noopFactory() + class C {} + + expect(Reflect.ownKeys(C)).not.toContain("_"); +} + +{ + @noopFactory() + class C { + @noopFactory() #p; + } + + expect(Reflect.ownKeys(C)).not.toContain("_"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/ctx-access-public-other-this/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/ctx-access-public-other-this/exec.js new file mode 100644 index 000000000000..8542e671a413 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/ctx-access-public-other-this/exec.js @@ -0,0 +1,39 @@ +function dec(v, context) { + context.addInitializer(function () { + this[context.name + 'Context'] = context; + }); + + return v; +} + +class Foo { + @dec + static accessor a; + + _b = 1; + + @dec + set b(v) { + this._b = v + 1; + } +} + +const obj = {}; +const foo = new Foo(); + +const aContext = Foo.aContext; +const bContext = foo.bContext; + +aContext.access.set(Foo, 123); + +bContext.access.set(foo, 123); + + +aContext.access.set(obj, 456); +bContext.access.set(obj, 456); + +expect(Foo.a).toBe(123); +expect(foo._b).toBe(124); + +expect(obj.a).toBe(456); +expect(obj.b).toBe(456); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/ctx-access-public-other-this/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/ctx-access-public-other-this/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/ctx-access-public-other-this/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-arguments/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-arguments/exec.js new file mode 100644 index 000000000000..bb1cd1c259f4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-arguments/exec.js @@ -0,0 +1,54 @@ +{ + let receivedArguments; + function decFactory(args) { + receivedArguments = args; + return x => x; + } + function B() { + class C { + @decFactory(arguments) #p; + } + } + + B(0); + expect(receivedArguments).toHaveLength(1); + expect(receivedArguments[0]).toBe(0); +} + +{ + function noop() {} + let receivedArguments; + function decFactory(args) { + receivedArguments = args; + return x => x; + } + function B() { + @noop + class C { + @decFactory(arguments) #p; + } + } + + B(0); + expect(receivedArguments).toHaveLength(1); + expect(receivedArguments[0]).toBe(0); +} + +{ + function noop() {} + let receivedArguments; + function decFactory(args) { + receivedArguments = args; + return x => x; + } + function B() { + @noop + class C { + @decFactory(arguments) static #p; + } + } + + B(0); + expect(receivedArguments).toHaveLength(1); + expect(receivedArguments[0]).toBe(0); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-arguments/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-arguments/options.json new file mode 100644 index 000000000000..e1a98d3e3876 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-arguments/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "16.9.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-new-target/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-new-target/exec.js new file mode 100644 index 000000000000..b20ee97b1b8f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-new-target/exec.js @@ -0,0 +1,86 @@ +{ + let receivedNewTarget; + function decFactory(target) { + receivedNewTarget = target; + return x => x; + } + function B() { + class C { + @decFactory(new.target) #p; + } + } + + new B(); + + expect(receivedNewTarget).toBe(B); +} + +{ + let receivedNewTarget; + function decFactory(target) { + receivedNewTarget = target; + return x => x; + } + function B() { + @decFactory(new.target) + class C { + #p; + } + } + + new B(); + + expect(receivedNewTarget).toBe(B); +} + +{ + function noop() {} + let receivedNewTarget; + function decFactory(target) { + receivedNewTarget = target; + return x => x; + } + function B() { + @noop + class C { + @decFactory(new.target) #p; + } + } + + new B(); + + expect(receivedNewTarget).toBe(B); +} + +{ + function noop() {} + let receivedNewTarget; + function decFactory(target) { + receivedNewTarget = target; + return x => x; + } + function B() { + @noop + class C { + @decFactory(new.target) static #p; + } + } + + new B(); + + expect(receivedNewTarget).toBe(B); +} + +{ + let C; + const newC = class {}; + function B () { + C = @(new.target) + class { + #p; + } + } + + Reflect.construct(B, [], function () { return newC }) + expect(C).toBe(newC); +} \ No newline at end of file diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-new-target/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-new-target/options.json new file mode 100644 index 000000000000..e1a98d3e3876 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-new-target/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "16.9.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-private-environment/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-private-environment/exec.js new file mode 100644 index 000000000000..4ae3da714ae6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-private-environment/exec.js @@ -0,0 +1,159 @@ +{ + let staticFns = [], fns = [] + let B; + + function capture(staticFn, fn) { + staticFns.push(staticFn); + fns.push(fn); + } + + function dummy() {} + + class A { + static #X = "A#X"; + #x = "a#x"; + constructor () { + B = class B { + static #X = "B#X"; + #x = "b#x"; + @(capture(_ => _.#X, _ => _.#x), dummy) method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) get getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static get getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) set setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) static set setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) property; + @(capture(_ => _.#X, _ => _.#x), dummy) static property; + @(capture(_ => _.#X, _ => _.#x), dummy) accessor accessor; + @(capture(_ => _.#X, _ => _.#x), dummy) static accessor accessor; + } + } + } + + let a = new A(), b = new B(); + + expect(staticFns.map(fn => fn(B)).join()).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); + expect(fns.map(fn => fn(b)).join()).toBe("b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x"); +} + +{ + let staticFns = [], fns = [] + let B; + + function capture(staticFn, fn) { + staticFns.push(staticFn); + fns.push(fn); + } + + function dummy() {} + + class A { + static #X = "A#X"; + #x = "a#x"; + constructor () { + B = class B { + static #X = "B#X"; + #x = "b#x"; + @(capture(_ => _.#X, _ => _.#x), dummy) #method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static #Method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) get #getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static get #Getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) set #setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) static set #Setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) #property; + @(capture(_ => _.#X, _ => _.#x), dummy) static #Property; + @(capture(_ => _.#X, _ => _.#x), dummy) accessor #accessor; + @(capture(_ => _.#X, _ => _.#x), dummy) static accessor #Accessor; + } + } + } + + let a = new A(), b = new B(); + + expect(staticFns.map(fn => fn(B)).join()).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); + expect(fns.map(fn => fn(b)).join()).toBe("b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x"); +} + +{ + let staticFns = [], fns = [] + let B; + + function capture(staticFn, fn) { + staticFns.push(staticFn); + fns.push(fn); + } + + function dummy() {} + + class A { + static #X = "A#X"; + #x = "a#x"; + constructor () { + B = + @(capture(_ => _.#X, _ => _.#x), dummy) + class B { + static #X = "B#X"; + #x = "b#x"; + @(capture(_ => _.#X, _ => _.#x), dummy) method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) get getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static get getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) set setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) static set setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) property; + @(capture(_ => _.#X, _ => _.#x), dummy) static property; + @(capture(_ => _.#X, _ => _.#x), dummy) accessor accessor; + @(capture(_ => _.#X, _ => _.#x), dummy) static accessor accessor; + } + } + } + + let a = new A(), b = new B(); + expect(staticFns.shift()(A)).toBe("A#X"); + expect(fns.shift()(a)).toBe("a#x"); + + expect(staticFns.map(fn => fn(B)).join()).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); + expect(fns.map(fn => fn(b)).join()).toBe("b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x"); +} + +{ + let staticFns = [], fns = [] + let B; + + function capture(staticFn, fn) { + staticFns.push(staticFn); + fns.push(fn); + } + + function dummy() {} + + class A { + static #X = "A#X"; + #x = "a#x"; + constructor () { + B = + @(capture(_ => _.#X, _ => _.#x), dummy) + class B { + static #X = "B#X"; + #x = "b#x"; + @(capture(_ => _.#X, _ => _.#x), dummy) #method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static #Method () {} + @(capture(_ => _.#X, _ => _.#x), dummy) get #getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) static get #Getter () {} + @(capture(_ => _.#X, _ => _.#x), dummy) set #setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) static set #Setter (v) {} + @(capture(_ => _.#X, _ => _.#x), dummy) #property; + @(capture(_ => _.#X, _ => _.#x), dummy) static #Property; + @(capture(_ => _.#X, _ => _.#x), dummy) accessor #accessor; + @(capture(_ => _.#X, _ => _.#x), dummy) static accessor #Accessor; + } + } + } + + let a = new A(), b = new B(); + expect(staticFns.shift()(A)).toBe("A#X"); + expect(fns.shift()(a)).toBe("a#x"); + + expect(staticFns.map(fn => fn(B)).join()).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); + expect(fns.map(fn => fn(b)).join()).toBe("b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x,b#x"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-getter-setter/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-getter-setter/exec.js new file mode 100644 index 000000000000..816f371e0268 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-getter-setter/exec.js @@ -0,0 +1,159 @@ +function noop() {} + +function BaseFactory(logs) { + return class A { + static get getter() { + logs.push("getter") + } + static set setter(v) { + logs.push("setter"); + } + } +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + class C { + @(super.setter = super.getter, noop) p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + class C { + @(super.setter = super.getter, noop) #p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + class C { + @(super.setter = super.getter, noop) accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) static p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) #p; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) static [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} + +{ + const logs = []; + class B extends BaseFactory(logs) { + static m() { + @noop + class C { + @(super.setter = super.getter, noop) static accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(logs.join()).toBe("getter,setter"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-getter-setter/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-getter-setter/options.json new file mode 100644 index 000000000000..e1a98d3e3876 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-getter-setter/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "16.9.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-property/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-property/exec.js new file mode 100644 index 000000000000..2ba4461a451f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-property/exec.js @@ -0,0 +1,148 @@ +function noop() {} + +{ + let receivedName; + class B extends class A {} { + static m() { + class C { + @(receivedName = super.name, noop) p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + class C { + @(receivedName = super.name, noop) #p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + class C { + @(receivedName = super.name, noop) accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) static p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) #p; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) static [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} + +{ + let receivedName; + class B extends class A {} { + static m() { + @noop + class C { + @(receivedName = super.name, noop) static accessor [(noop(), "p")]; + } + } + } + + B.m(); + expect(receivedName).toBe("A"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-property/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-property/options.json new file mode 100644 index 000000000000..e1a98d3e3876 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-super-property/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "16.9.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-this/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-this/exec.js new file mode 100644 index 000000000000..0bf278714343 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-this/exec.js @@ -0,0 +1,95 @@ +{ + let receivedName; + function decFactory(name) { + receivedName = name; + return x => x; + } + class B { + static m() { + class C { + @decFactory(this.name) #p; + } + } + } + + B.m(); + expect(receivedName).toBe("B"); +} + +{ + let receivedName; + function decFactory(name) { + receivedName = name; + return x => x; + } + class B { + static m() { + @decFactory(this.name) + class C { + #p; + } + } + } + + B.m(); + expect(receivedName).toBe("B"); +} + +{ + let receivedLength; + function decFactory(length) { + receivedLength = length; + return x => x; + } + function noop() {} + class B { + static m() { + @noop + class C { + @decFactory(this.length) #p; + constructor(bar) {} + } + } + constructor(foo, bar) {} + } + + B.m(); + expect(receivedLength).toBe(2); +} + +{ + let receivedLength; + function decFactory(length) { + receivedLength = length; + return x => x; + } + function noop() {} + class B { + static m() { + @noop + class C { + @decFactory(this.length) static #p; + constructor(bar) {} + } + } + constructor(foo, bar) {} + } + + B.m(); + expect(receivedLength).toBe(2); +} + +{ + let C; + const newC = class {}; + const B = () => newC; + B.m = function () { + C = @(this) + class { + #p; + } + } + + B.m(); + expect(C).toBe(newC); +} \ No newline at end of file diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-this/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-this/options.json new file mode 100644 index 000000000000..e1a98d3e3876 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-this/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "16.9.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield-private-super-property/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield-private-super-property/exec.js new file mode 100644 index 000000000000..4766b6546da4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield-private-super-property/exec.js @@ -0,0 +1,99 @@ +{ + let B; + + class CaptureFactory { + static *id(fn) { + yield fn; + } + } + + function dummy() {} + + class A extends CaptureFactory { + static #X = "A#X"; + static *[Symbol.iterator] () { + B = class B { + static #X = "B#X"; + @(yield* super.id(_ => _.#X), dummy) method () {} + @(yield* super.id(_ => _.#X), dummy) static method () {} + @(yield* super.id(_ => _.#X), dummy) get getter () {} + @(yield* super.id(_ => _.#X), dummy) static get getter () {} + @(yield* super.id(_ => _.#X), dummy) set setter (v) {} + @(yield* super.id(_ => _.#X), dummy) static set setter (v) {} + @(yield* super.id(_ => _.#X), dummy) property; + @(yield* super.id(_ => _.#X), dummy) static property; + @(yield* super.id(_ => _.#X), dummy) accessor accessor; + @(yield* super.id(_ => _.#X), dummy) static accessor accessor; + } + } + } + + expect([...A].map(fn => fn(B)).join(",")).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); +} + +{ + let B; + + class CaptureFactory { + static *id(fn) { + yield fn; + } + } + + function dummy() {} + + class A extends CaptureFactory { + static #X = "A#X"; + static *[Symbol.iterator] () { + B = @dummy + class B { + static #X = "B#X"; + @(yield* super.id(_ => _.#X), dummy) method () {} + @(yield* super.id(_ => _.#X), dummy) static method () {} + @(yield* super.id(_ => _.#X), dummy) get getter () {} + @(yield* super.id(_ => _.#X), dummy) static get getter () {} + @(yield* super.id(_ => _.#X), dummy) set setter (v) {} + @(yield* super.id(_ => _.#X), dummy) static set setter (v) {} + @(yield* super.id(_ => _.#X), dummy) property; + @(yield* super.id(_ => _.#X), dummy) static property; + @(yield* super.id(_ => _.#X), dummy) accessor accessor; + @(yield* super.id(_ => _.#X), dummy) static accessor accessor; + } + } + } + + expect([...A].map(fn => fn(B)).join(",")).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); +} + +{ + let B; + + class CaptureFactory { + static *id(fn) { + yield fn; + } + } + + function dummy() {} + + class A extends CaptureFactory { + static #X = "A#X"; + static *[Symbol.iterator] () { + B = class { + static #X = "B#X"; + @(yield* super.id(_ => _.#X), dummy) #method () {} + @(yield* super.id(_ => _.#X), dummy) static #Method () {} + @(yield* super.id(_ => _.#X), dummy) get #getter () {} + @(yield* super.id(_ => _.#X), dummy) static get #Getter () {} + @(yield* super.id(_ => _.#X), dummy) set #setter (v) {} + @(yield* super.id(_ => _.#X), dummy) static set #Setter (v) {} + @(yield* super.id(_ => _.#X), dummy) #property; + @(yield* super.id(_ => _.#X), dummy) static #Property; + @(yield* super.id(_ => _.#X), dummy) accessor #accessor; + @(yield* super.id(_ => _.#X), dummy) static accessor #Accessor; + } + } + } + + expect([...A].map(fn => fn(B)).join(",")).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield-private-super-property/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield-private-super-property/options.json new file mode 100644 index 000000000000..e1a98d3e3876 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield-private-super-property/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "16.9.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield/exec.js new file mode 100644 index 000000000000..166efb735a01 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield/exec.js @@ -0,0 +1,162 @@ +const noop = () => {}; +{ + const log = { + *[Symbol.iterator]() { + + class Foo { + @(yield 1, noop) method() {} + @(yield 2, noop) static method() {} + @(yield 3, noop) field; + @(yield 4, noop) static field; + @(yield 5, noop) get getter() { + return; + } + @(yield 6, noop) static get getter() { + return; + } + @(yield 7, noop) set setter(x) {} + @(yield 8, noop) static set setter(x) {} + @(yield 9, noop) accessor accessor; + @(yield 10, noop) static accessor accessor; + } + }, + }; + expect([...log].join()).toBe("1,2,3,4,5,6,7,8,9,10"); +} +{ + let Foo; + const log = { + *[Symbol.iterator]() { + + Foo = class { + @(yield 0, noop) [(yield 1, "method")]() {} + @(yield 2, noop) static method() {} + @(yield 3, noop) field; + @(yield 4, noop) static field; + @(yield 5, noop) get getter() { + return; + } + @(yield 6, noop) static get getter() { + return; + } + @(yield 7, noop) set setter(x) {} + @(yield 8, noop) static set setter(x) {} + @(yield 9, noop) accessor accessor; + @(yield 10, noop) static accessor accessor; + } + }, + }; + expect([...log].join()).toBe("0,1,2,3,4,5,6,7,8,9,10"); + expect((new Foo())).toHaveProperty("method"); +} +{ + const log = { + *[Symbol.iterator]() { + @(yield 0, noop) + class Foo { + @(yield 1, noop) method() {} + @(yield 2, noop) static method() {} + @(yield 3, noop) field; + @(yield 4, noop) static field; + @(yield 5, noop) get getter() { + return; + } + @(yield 6, noop) static get getter() { + return; + } + @(yield 7, noop) set setter(x) {} + @(yield 8, noop) static set setter(x) {} + @(yield 9, noop) accessor accessor; + @(yield 10, noop) static accessor accessor; + } + }, + }; + expect([...log].join()).toBe("0,1,2,3,4,5,6,7,8,9,10"); +} + +{ + let Foo; + const log = { + *[Symbol.iterator]() { + Foo = @(yield 0, noop) + class { + @(yield 1, noop) method() {} + @(yield 2, noop) static method() {} + @(yield 3, noop) field; + @(yield 4, noop) static field; + @(yield 5, noop) get getter() { + return; + } + @(yield 6, noop) static get getter() { + return; + } + @(yield 7, noop) set setter(x) {} + @(yield 8, noop) static set setter(x) {} + @(yield 9, noop) accessor accessor; + @(yield 10, noop) static accessor [(yield 11, "accessor")]; + } + }, + }; + expect([...log].join()).toBe("0,1,2,3,4,5,6,7,8,9,10,11"); + expect(Foo).toHaveProperty("accessor"); +} + +{ + const id = function* (x) { + yield x; + } + const log = { + *[Symbol.iterator]() { + @(yield 0, noop) + @(yield 1, noop) + class Foo { + method() {} + static method() {} + field; + static field; + get getter() { + return; + } + static get getter() { + return; + } + set setter(x) {} + static set setter(x) {} + accessor accessor; + static accessor accessor; + } + }, + }; + expect([...log].join()).toBe("0,1"); +} + +{ + let C; + const iter = (function* iterFactory() { + C = + @(yield) + @(yield) + class C { + method() {} + static method() {} + field; + static field; + get getter() { + return; + } + static get getter() { + return; + } + set setter(x) {} + static set setter(x) {} + accessor accessor; + static accessor accessor; + }; + })(); + const C1 = class {}, + C2 = class {}; + iter.next(); + iter.next(() => C1); + iter.next(() => C2); + expect(C).toBe(C1); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield/options.json new file mode 100644 index 000000000000..6c1e089b4472 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/decorator-evaluation-yield/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "12.0.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initField-existing-derived-constructor/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initField-existing-derived-constructor/exec.js new file mode 100644 index 000000000000..ff55f12cd539 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initField-existing-derived-constructor/exec.js @@ -0,0 +1,175 @@ +{ + let self, a, initCalled; + + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + + class B { + constructor(s) { + a = s; + } + } + + class A extends B { + constructor() { + let a = 2; + self = super(a); + } + + @deco + accessor foo = 42; + } + + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} + +{ + const dec = ({ get, set }) => { + return { + get() { + return get.call(this) + 100; + }, + + set(v) { + set.call(this, v); + }, + } + }; + + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + + { + ("super() nested within another constructor should not be transformed"); + let log = []; + class A extends B { + constructor() { + log.push(super(3).method()); + new (class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("3,4"); + expect(a.foo).toBe(142); + } + + { + ("super() not in decorated derived constructor should not be transformed: computed key"); + let log = []; + new (class Dummy extends B { + constructor() { + let key; + class A extends B { + constructor() { + log.push(super(6).method()); + } + + @dec + accessor foo = 42; + + [((key = super(5).method()), log.push(key), key)]; + } + + const a = new A(); + + expect(a.foo).toBe(142); + } + })(); + + expect(log + "").toBe("5,6"); + } + + { + ("super() in decorator expression within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + new (class extends B { + constructor() { + class A extends B { + constructor() { + log.push(super(8).method()); + } + + @dec + accessor foo = 42; + + @noop(log.push(super(7).method())) noop() {} + } + + const a = new A(); + expect(a.foo).toBe(142); + } + })(); + + expect(log + "").toBe("7,8"); + } + + { + ("super() within decorated derived constructor should be transformed: computed key"); + let log = []; + class A extends B { + constructor() { + let key; + new (class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [((key = super(9).method()), log.push(key), key)]; + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("9,10"); + expect(a.foo).toBe(142); + } + + { + ("super() within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + class A extends B { + constructor() { + new (class Dummy extends B { + constructor() { + log.push(super(12).method()); + } + @noop(log.push(super(11).method())) noop() {} + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("11,12"); + expect(a.foo).toBe(142); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initField-existing-derived-constructor/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initField-existing-derived-constructor/input.js new file mode 100644 index 000000000000..ff55f12cd539 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initField-existing-derived-constructor/input.js @@ -0,0 +1,175 @@ +{ + let self, a, initCalled; + + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + + class B { + constructor(s) { + a = s; + } + } + + class A extends B { + constructor() { + let a = 2; + self = super(a); + } + + @deco + accessor foo = 42; + } + + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} + +{ + const dec = ({ get, set }) => { + return { + get() { + return get.call(this) + 100; + }, + + set(v) { + set.call(this, v); + }, + } + }; + + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + + { + ("super() nested within another constructor should not be transformed"); + let log = []; + class A extends B { + constructor() { + log.push(super(3).method()); + new (class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("3,4"); + expect(a.foo).toBe(142); + } + + { + ("super() not in decorated derived constructor should not be transformed: computed key"); + let log = []; + new (class Dummy extends B { + constructor() { + let key; + class A extends B { + constructor() { + log.push(super(6).method()); + } + + @dec + accessor foo = 42; + + [((key = super(5).method()), log.push(key), key)]; + } + + const a = new A(); + + expect(a.foo).toBe(142); + } + })(); + + expect(log + "").toBe("5,6"); + } + + { + ("super() in decorator expression within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + new (class extends B { + constructor() { + class A extends B { + constructor() { + log.push(super(8).method()); + } + + @dec + accessor foo = 42; + + @noop(log.push(super(7).method())) noop() {} + } + + const a = new A(); + expect(a.foo).toBe(142); + } + })(); + + expect(log + "").toBe("7,8"); + } + + { + ("super() within decorated derived constructor should be transformed: computed key"); + let log = []; + class A extends B { + constructor() { + let key; + new (class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [((key = super(9).method()), log.push(key), key)]; + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("9,10"); + expect(a.foo).toBe(142); + } + + { + ("super() within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + class A extends B { + constructor() { + new (class Dummy extends B { + constructor() { + log.push(super(12).method()); + } + @noop(log.push(super(11).method())) noop() {} + })(); + } + + @dec + accessor foo = 42; + } + + const a = new A(); + + expect(log + "").toBe("11,12"); + expect(a.foo).toBe(142); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initField-existing-derived-constructor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initField-existing-derived-constructor/output.js new file mode 100644 index 000000000000..6bbac716467e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initField-existing-derived-constructor/output.js @@ -0,0 +1,205 @@ +{ + let _init_foo, _init_extra_foo; + let self, a, initCalled; + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + class B { + constructor(s) { + a = s; + } + } + class A extends B { + static { + [_init_foo, _init_extra_foo] = babelHelpers.applyDecs2311(this, [], [[deco, 1, "foo"]], 0, void 0, B).e; + } + constructor() { + let a = 2; + self = (super(a), _init_extra_foo(this)); + } + #A = _init_foo(this, 42); + get foo() { + return this.#A; + } + set foo(v) { + this.#A = v; + } + } + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} +{ + const dec = ({ + get, + set + }) => { + return { + get() { + return get.call(this) + 100; + }, + set(v) { + set.call(this, v); + } + }; + }; + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + { + let _init_foo2, _init_extra_foo2; + "super() nested within another constructor should not be transformed"; + let log = []; + class A extends B { + static { + [_init_foo2, _init_extra_foo2] = babelHelpers.applyDecs2311(this, [], [[dec, 1, "foo"]], 0, void 0, B).e; + } + constructor() { + log.push((super(3), _init_extra_foo2(this)).method()); + new class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + }(); + } + #A = _init_foo2(this, 42); + get foo() { + return this.#A; + } + set foo(v) { + this.#A = v; + } + } + const a = new A(); + expect(log + "").toBe("3,4"); + expect(a.foo).toBe(142); + } + { + "super() not in decorated derived constructor should not be transformed: computed key"; + let log = []; + new class Dummy extends B { + constructor() { + let _init_foo3, _init_extra_foo3, _computedKey; + let key; + class A extends B { + static { + [_init_foo3, _init_extra_foo3] = babelHelpers.applyDecs2311(this, [], [[dec, 1, "foo"]], 0, void 0, B).e; + } + constructor() { + log.push(super(6).method()); + } + #A = _init_foo3(this, 42); + get foo() { + return this.#A; + } + set foo(v) { + this.#A = v; + } + [_computedKey = (key = super(5).method(), log.push(key), key)] = void _init_extra_foo3(this); + } + const a = new A(); + expect(a.foo).toBe(142); + } + }(); + expect(log + "").toBe("5,6"); + } + { + "super() in decorator expression within decorated derived constructor should be transformed: decorator expression"; + let log = []; + const noop = () => fn => fn; + new class extends B { + constructor() { + let _initProto, _init_foo4, _init_extra_foo4, _noopDecs; + class A extends B { + static { + [_init_foo4, _init_extra_foo4, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 1, "foo"], [_noopDecs, 2, "noop"]], 0, void 0, B).e; + } + constructor() { + log.push((super(8), _init_extra_foo4(this)).method()); + } + #A = (_initProto(this), _init_foo4(this, 42)); + get [(_noopDecs = noop(log.push(super(7).method())), "foo")]() { + return this.#A; + } + set foo(v) { + this.#A = v; + } + noop() {} + } + const a = new A(); + expect(a.foo).toBe(142); + } + }(); + expect(log + "").toBe("7,8"); + } + { + let _init_foo5, _init_extra_foo5; + "super() within decorated derived constructor should be transformed: computed key"; + let log = []; + class A extends B { + static { + [_init_foo5, _init_extra_foo5] = babelHelpers.applyDecs2311(this, [], [[dec, 1, "foo"]], 0, void 0, B).e; + } + constructor() { + let key; + new class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [(key = (super(9), _init_extra_foo5(this)).method(), log.push(key), key)]; + }(); + } + #A = _init_foo5(this, 42); + get foo() { + return this.#A; + } + set foo(v) { + this.#A = v; + } + } + const a = new A(); + expect(log + "").toBe("9,10"); + expect(a.foo).toBe(142); + } + { + let _init_foo6, _init_extra_foo6; + "super() within decorated derived constructor should be transformed: decorator expression"; + let log = []; + const noop = () => fn => fn; + class A extends B { + static { + [_init_foo6, _init_extra_foo6] = babelHelpers.applyDecs2311(this, [], [[dec, 1, "foo"]], 0, void 0, B).e; + } + constructor() { + let _initProto2, _noopDecs2; + new class Dummy extends B { + static { + [_initProto2] = babelHelpers.applyDecs2311(this, [], [[_noopDecs2, 2, "noop"]], 0, void 0, B).e; + } + constructor() { + log.push(_initProto2(super(12)).method()); + } + [(_noopDecs2 = noop(log.push((super(11), _init_extra_foo6(this)).method())), "noop")]() {} + }(); + } + #A = _init_foo6(this, 42); + get foo() { + return this.#A; + } + set foo(v) { + this.#A = v; + } + } + const a = new A(); + expect(log + "").toBe("11,12"); + expect(a.foo).toBe(142); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor-multiple-super/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor-multiple-super/input.js new file mode 100644 index 000000000000..a8da039942d6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor-multiple-super/input.js @@ -0,0 +1,24 @@ +const dec = () => {}; +class A extends B { + constructor() { + if (Math.random() > 0.5) { + super(true); + } else { + super(false); + } + } + + @deco + method() {} +} + +class C extends B { + constructor() { + try { + super(super(), null.x); + } catch {} + } + + @deco + method() {} +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor-multiple-super/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor-multiple-super/output.js new file mode 100644 index 000000000000..90d63d282a40 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor-multiple-super/output.js @@ -0,0 +1,27 @@ +var _B, _B2; +let _initProto, _initProto2; +const dec = () => {}; +class A extends (_B = B) { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[deco, 2, "method"]], 0, void 0, _B).e; + } + constructor() { + if (Math.random() > 0.5) { + _initProto(super(true)); + } else { + _initProto(super(false)); + } + } + method() {} +} +class C extends (_B2 = B) { + static { + [_initProto2] = babelHelpers.applyDecs2311(this, [], [[deco, 2, "method"]], 0, void 0, _B2).e; + } + constructor() { + try { + _initProto2(super(_initProto2(super()), null.x)); + } catch {} + } + method() {} +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/exec.js new file mode 100644 index 000000000000..4edba29a60bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/exec.js @@ -0,0 +1,173 @@ +{ + let self, a, initCalled; + + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + + class B { + constructor(s) { + a = s; + } + } + + class A extends B { + constructor() { + let a = 2; + self = super(a); + } + + @deco + method() {} + } + + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} + +{ + const dec = (fn) => { + return function () { + return fn.call(this) + 100; + }; + }; + + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + + { + ("super() nested within another constructor should not be transformed"); + let log = []; + class A extends B { + constructor() { + log.push(super(3).method()); + new (class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("103,4"); + } + + { + ("super() not in decorated derived constructor should not be transformed: computed key"); + let log = []; + new (class Dummy extends B { + constructor() { + let key; + class A extends B { + constructor() { + log.push(super(6).method()); + } + + @dec + method() { + return this.a; + } + + [((key = super(5).method()), log.push(key), key)]; + } + + new A(); + } + })(); + + expect(log + "").toBe("5,106"); + } + + { + ("super() in decorator expression within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + new (class extends B { + constructor() { + class A extends B { + constructor() { + log.push(super(8).method()); + } + + @dec + method() { + return this.a; + } + + @noop(log.push(super(7).method())) noop() {} + } + + new A(); + } + })(); + + expect(log + "").toBe("7,108"); + } + + { + ("super() within decorated derived constructor should be transformed: computed key"); + let log = []; + class A extends B { + constructor() { + let key; + new (class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [((key = super(9).method()), log.push(key), key)]; + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("109,10"); + } + + { + ("super() within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + class A extends B { + constructor() { + new (class Dummy extends B { + constructor() { + log.push(super(12).method()); + } + @noop(log.push(super(11).method())) noop() {} + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("111,12"); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/input.js new file mode 100644 index 000000000000..4edba29a60bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/input.js @@ -0,0 +1,173 @@ +{ + let self, a, initCalled; + + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + + class B { + constructor(s) { + a = s; + } + } + + class A extends B { + constructor() { + let a = 2; + self = super(a); + } + + @deco + method() {} + } + + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} + +{ + const dec = (fn) => { + return function () { + return fn.call(this) + 100; + }; + }; + + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + + { + ("super() nested within another constructor should not be transformed"); + let log = []; + class A extends B { + constructor() { + log.push(super(3).method()); + new (class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("103,4"); + } + + { + ("super() not in decorated derived constructor should not be transformed: computed key"); + let log = []; + new (class Dummy extends B { + constructor() { + let key; + class A extends B { + constructor() { + log.push(super(6).method()); + } + + @dec + method() { + return this.a; + } + + [((key = super(5).method()), log.push(key), key)]; + } + + new A(); + } + })(); + + expect(log + "").toBe("5,106"); + } + + { + ("super() in decorator expression within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + new (class extends B { + constructor() { + class A extends B { + constructor() { + log.push(super(8).method()); + } + + @dec + method() { + return this.a; + } + + @noop(log.push(super(7).method())) noop() {} + } + + new A(); + } + })(); + + expect(log + "").toBe("7,108"); + } + + { + ("super() within decorated derived constructor should be transformed: computed key"); + let log = []; + class A extends B { + constructor() { + let key; + new (class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [((key = super(9).method()), log.push(key), key)]; + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("109,10"); + } + + { + ("super() within decorated derived constructor should be transformed: decorator expression"); + let log = []; + const noop = () => (fn) => fn; + class A extends B { + constructor() { + new (class Dummy extends B { + constructor() { + log.push(super(12).method()); + } + @noop(log.push(super(11).method())) noop() {} + })(); + } + + @dec + method() { + return this.a; + } + } + + new A(); + + expect(log + "").toBe("111,12"); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/output.js new file mode 100644 index 000000000000..6a60e12df972 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initProto-existing-derived-constructor/output.js @@ -0,0 +1,166 @@ +{ + let _initProto; + let self, a, initCalled; + function deco(_, context) { + context.addInitializer(() => { + initCalled = true; + }); + } + class B { + constructor(s) { + a = s; + } + } + class A extends B { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[deco, 2, "method"]], 0, void 0, B).e; + } + constructor() { + let a = 2; + self = _initProto(super(a)); + } + method() {} + } + let instance = new A(); + expect(self).toBe(instance); + expect(a).toBe(2); + expect(initCalled).toBe(true); +} +{ + const dec = fn => { + return function () { + return fn.call(this) + 100; + }; + }; + class B { + constructor(v) { + this.a = v; + } + method() { + return this.a; + } + } + { + let _initProto2; + "super() nested within another constructor should not be transformed"; + let log = []; + class A extends B { + static { + [_initProto2] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "method"]], 0, void 0, B).e; + } + constructor() { + log.push(_initProto2(super(3)).method()); + new class Dummy extends B { + constructor() { + log.push(super(4).method()); + } + }(); + } + method() { + return this.a; + } + } + new A(); + expect(log + "").toBe("103,4"); + } + { + "super() not in decorated derived constructor should not be transformed: computed key"; + let log = []; + new class Dummy extends B { + constructor() { + let _initProto3, _computedKey; + let key; + class A extends B { + static { + [_initProto3] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "method"]], 0, void 0, B).e; + } + constructor() { + log.push(super(6).method()); + } + method() { + return this.a; + } + [_computedKey = (key = super(5).method(), log.push(key), key)] = void _initProto3(this); + } + new A(); + } + }(); + expect(log + "").toBe("5,106"); + } + { + "super() in decorator expression within decorated derived constructor should be transformed: decorator expression"; + let log = []; + const noop = () => fn => fn; + new class extends B { + constructor() { + let _initProto4, _noopDecs; + class A extends B { + static { + [_initProto4] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "method"], [_noopDecs, 2, "noop"]], 0, void 0, B).e; + } + constructor() { + log.push(_initProto4(super(8)).method()); + } + [(_noopDecs = noop(log.push(super(7).method())), "method")]() { + return this.a; + } + noop() {} + } + new A(); + } + }(); + expect(log + "").toBe("7,108"); + } + { + let _initProto5; + "super() within decorated derived constructor should be transformed: computed key"; + let log = []; + class A extends B { + static { + [_initProto5] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "method"]], 0, void 0, B).e; + } + constructor() { + let key; + new class Dummy extends B { + constructor() { + log.push(super(10).method()); + } + [(key = _initProto5(super(9)).method(), log.push(key), key)]; + }(); + } + method() { + return this.a; + } + } + new A(); + expect(log + "").toBe("109,10"); + } + { + let _initProto6; + "super() within decorated derived constructor should be transformed: decorator expression"; + let log = []; + const noop = () => fn => fn; + class A extends B { + static { + [_initProto6] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "method"]], 0, void 0, B).e; + } + constructor() { + let _initProto7, _noopDecs2; + new class Dummy extends B { + static { + [_initProto7] = babelHelpers.applyDecs2311(this, [], [[_noopDecs2, 2, "noop"]], 0, void 0, B).e; + } + constructor() { + log.push(_initProto7(super(12)).method()); + } + [(_noopDecs2 = noop(log.push(_initProto6(super(11)).method())), "noop")]() {} + }(); + } + method() { + return this.a; + } + } + new A(); + expect(log + "").toBe("111,12"); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initializer-property-ignored/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initializer-property-ignored/exec.js new file mode 100644 index 000000000000..2828e1c22408 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initializer-property-ignored/exec.js @@ -0,0 +1,25 @@ +let init = false; +let initializer = false; + +function decorator() { + return { + get init() { + init = true; + return () => {}; + }, + get initializer() { + initializer = true; + return () => {}; + } + }; +} + +class A { + @decorator + accessor x; +} + +new A(); + +expect(init).toBe(true); +expect(initializer).toBe(false); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initializer-property-ignored/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initializer-property-ignored/options.json new file mode 100644 index 000000000000..6c1e089b4472 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/initializer-property-ignored/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "12.0.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/invalid-non-callable-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/invalid-non-callable-decorators/exec.js new file mode 100644 index 000000000000..9249424de280 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/invalid-non-callable-decorators/exec.js @@ -0,0 +1,43 @@ +{ + "invalid non-callable class decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => @nonCallable class {}).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable field decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable field }).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable accessor decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable accessor accessor; }).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable method decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable method() {} }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined class decorators"; + expect(() => @(void 0) class {}).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined field decorators"; + expect(() => class { @(void 0) field }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined accessor decorators"; + expect(() => class { @(void 0) accessor accessor; }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined method decorators"; + expect(() => class { @(void 0) method() {} }).toThrow("A decorator must be a function"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/options.json new file mode 100644 index 000000000000..efb3660a1787 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/options.json @@ -0,0 +1,4 @@ +{ + "minNodeVersion": "16.0.0", + "plugins": [["proposal-decorators", { "version": "2023-11" }]] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/exec.js new file mode 100644 index 000000000000..cc68db97acb9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/exec.js @@ -0,0 +1,145 @@ +{ + "class binding in plain class, decorated field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + capture(() => K); + assertUninitialized(() => K); + + class K { + @capture(() => K) @assertUninitialized(() => K) [(capture(() => K), assertUninitialized(() => K))] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E, E, E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + K = null; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(() => K) + @assertUninitialized(() => K) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(() => K) [capture(() => K)] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + [K = null] = []; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated static field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(() => K) + @assertUninitialized(() => K) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(() => K) static [capture(() => K)] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + ({ K = null } = {}); + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated static method, and computed keys with await"; + (async () => { + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(await (() => K)) + @assertUninitialized(await (() => K)) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(await (() => K)) static [capture(await (() => K))]() {} + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + [K] = [null]; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); + })() +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/input.js new file mode 100644 index 000000000000..cc68db97acb9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/input.js @@ -0,0 +1,145 @@ +{ + "class binding in plain class, decorated field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + capture(() => K); + assertUninitialized(() => K); + + class K { + @capture(() => K) @assertUninitialized(() => K) [(capture(() => K), assertUninitialized(() => K))] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E, E, E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + K = null; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(() => K) + @assertUninitialized(() => K) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(() => K) [capture(() => K)] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + [K = null] = []; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated static field, and computed keys" + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(() => K) + @assertUninitialized(() => K) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(() => K) static [capture(() => K)] + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + ({ K = null } = {}); + + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} + +{ + "class binding in decorated class, decorated static method, and computed keys with await"; + (async () => { + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {} + } + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {} + } + } + + @capture(await (() => K)) + @assertUninitialized(await (() => K)) + class K { + //todo: add the assertUninitialized decorator when we properly implement class tdz + @capture(await (() => K)) static [capture(await (() => K))]() {} + } + + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + + [K] = [null]; + + expect(fns.map(fn => fn())).toEqual([null, C, C]); + })() +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/options.json new file mode 100644 index 000000000000..6c1e089b4472 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-static-block" + ], + "minNodeVersion": "12.0.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/output.js new file mode 100644 index 000000000000..aabdc06e9a5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/outer-class-binding-mutated/output.js @@ -0,0 +1,176 @@ +{ + let _computedKeyDecs, _computedKey, _init_computedKey, _init_extra_computedKey; + "class binding in plain class, decorated field, and computed keys"; + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {}; + }; + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {}; + } + }; + capture(() => K); + assertUninitialized(() => K); + class K { + static #_ = [_init_computedKey, _init_extra_computedKey] = babelHelpers.applyDecs2311(this, [], [[_computedKeyDecs, 0, _computedKey]]).e; + constructor() { + _init_extra_computedKey(this); + } + [(_computedKeyDecs = [capture(() => K), assertUninitialized(() => K)], _computedKey = babelHelpers.toPropertyKey((capture(() => K), assertUninitialized(() => K))))] = _init_computedKey(this); + } + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E, E, E]); + const C = K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + K = null; + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} +{ + let _initClass, _classDecs, _computedKeyDecs2, _computedKey2, _init_computedKey2, _init_extra_computedKey2; + "class binding in decorated class, decorated field, and computed keys"; + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {}; + }; + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {}; + } + }; + _classDecs = [capture(() => _K), assertUninitialized(() => _K)]; + let _K, _t_K; + { + let _K; + class K { + static #_ = { + e: [_init_computedKey2, _init_extra_computedKey2], + c: [_K, _initClass] + } = babelHelpers.applyDecs2311(this, _classDecs, [[_computedKeyDecs2, 0, _computedKey2]]); + constructor() { + _init_extra_computedKey2(this); + } + //todo: add the assertUninitialized decorator when we properly implement class tdz + [(_computedKeyDecs2 = capture(() => _K), _computedKey2 = babelHelpers.toPropertyKey(capture(() => _K)))] = _init_computedKey2(this); + static #_2 = _initClass(); + } + _t_K = _K; + } + _K = _t_K; + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + const C = _K; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + [_K = null] = []; + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} +{ + let _initClass2, _classDecs2, _computedKeyDecs3, _computedKey3, _init_computedKey3, _init_extra_computedKey3; + "class binding in decorated class, decorated static field, and computed keys"; + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {}; + }; + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {}; + } + }; + _classDecs2 = [capture(() => _K2), assertUninitialized(() => _K2)]; + let _K2, _t_K2; + { + let _K2; + new class extends babelHelpers.identity { + static [class K { + static [(_computedKeyDecs3 = capture(() => _K2), _computedKey3 = babelHelpers.toPropertyKey(capture(() => _K2)), "_")]; + static #_ = (() => { + delete this._; + ({ + e: [_init_computedKey3, _init_extra_computedKey3], + c: [_K2, _initClass2] + } = babelHelpers.applyDecs2311(this, _classDecs2, [[_computedKeyDecs3, 8, _computedKey3]])); + })(); + }]; + //todo: add the assertUninitialized decorator when we properly implement class tdz + [_computedKey3] = _init_computedKey3(); + constructor() { + super(_K2), (() => { + _init_extra_computedKey3(); + })(), _initClass2(); + } + }(); + _t_K2 = _K2; + } + _K2 = _t_K2; + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + const C = _K2; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + ({ + K: _K2 = null + } = {}); + expect(fns.map(fn => fn())).toEqual([null, C, C]); +} +{ + "class binding in decorated class, decorated static method, and computed keys with await"; + (async (_initStatic, _initClass3, _classDecs3, _computedKeyDecs4, _computedKey4) => { + const errs = []; + const fns = []; + const capture = function (fn) { + fns.push(fn); + return () => {}; + }; + const assertUninitialized = function (fn) { + try { + fn(); + } catch (err) { + errs.push(err); + } finally { + return () => {}; + } + }; + _classDecs3 = [capture(await (() => _K3)), assertUninitialized(await (() => _K3))]; + let _K3, _t_K3; + { + let _K3; + class K { + static #_ = (() => { + ({ + e: [_initStatic], + c: [_K3, _initClass3] + } = babelHelpers.applyDecs2311(this, _classDecs3, [[_computedKeyDecs4, 10, _computedKey4]])); + _initStatic(this); + })(); + //todo: add the assertUninitialized decorator when we properly implement class tdz + static [(_computedKeyDecs4 = capture(await (() => _K3)), _computedKey4 = babelHelpers.toPropertyKey(capture(await (() => _K3))))]() {} + static #_2 = _initClass3(); + } + _t_K3 = _K3; + } + _K3 = _t_K3; + const E = ReferenceError; + expect(errs.map(e => e.constructor)).toEqual([E]); + const C = _K3; + expect(fns.map(fn => fn())).toEqual([C, C, C]); + [_K3] = [null]; + expect(fns.map(fn => fn())).toEqual([null, C, C]); + })(); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-keys-in-enclosing-class/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-keys-in-enclosing-class/input.js new file mode 100644 index 000000000000..0e7ac6161824 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-keys-in-enclosing-class/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class A { + #A = 1; + static B = class B extends A { + accessor a = 2; + + getA() { + return this.#A; + } + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-keys-in-enclosing-class/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-keys-in-enclosing-class/output.js new file mode 100644 index 000000000000..ec3d19f84d2a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-keys-in-enclosing-class/output.js @@ -0,0 +1,16 @@ +const dec = () => {}; +class A { + #A = 1; + static B = class B extends A { + #B = 2; + get a() { + return this.#B; + } + set a(v) { + this.#B = v; + } + getA() { + return this.#A; + } + }; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-name-in-class-decorator/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-name-in-class-decorator/exec.js new file mode 100644 index 000000000000..f37dda0b1d8c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-name-in-class-decorator/exec.js @@ -0,0 +1,14 @@ +let called = false; + +class A { + static #x() { called = true } + constructor() { + @(A.#x) + class B extends A { + static #x() { throw new Error("Should not be called") } + } + } +} + +new A(); +expect(called).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-name-in-class-decorator/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-name-in-class-decorator/input.js new file mode 100644 index 000000000000..f37dda0b1d8c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-name-in-class-decorator/input.js @@ -0,0 +1,14 @@ +let called = false; + +class A { + static #x() { called = true } + constructor() { + @(A.#x) + class B extends A { + static #x() { throw new Error("Should not be called") } + } + } +} + +new A(); +expect(called).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-name-in-class-decorator/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-name-in-class-decorator/output.js new file mode 100644 index 000000000000..53c06f2a59d3 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/private-name-in-class-decorator/output.js @@ -0,0 +1,26 @@ +let called = false; +class A { + static #x() { + called = true; + } + constructor() { + let _initClass, _classDecs; + _classDecs = [A, A.#x]; + let _B; + new class extends babelHelpers.identity { + static [class B extends A { + static { + [_B, _initClass] = babelHelpers.applyDecs2311(this, _classDecs, [], 1, void 0, A).c; + } + }]; + #x() { + throw new Error("Should not be called"); + } + constructor() { + super(_B), _initClass(); + } + }(); + } +} +new A(); +expect(called).toBe(true); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-in-body/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-in-body/input.js new file mode 100644 index 000000000000..e2d8ecdd6283 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-in-body/input.js @@ -0,0 +1,6 @@ +const dec = () => {}; +class Foo { + @dec #x() { + this.#x = 123; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-in-body/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-in-body/options.json new file mode 100644 index 000000000000..eb9bd0d7e9c5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-in-body/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Decorated private methods are read-only, but \"#x\" is updated via this expression." +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-array-pattern/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-array-pattern/input.js new file mode 100644 index 000000000000..53848c42cb07 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-array-pattern/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec #x() {} + + bar() { + ([this.#x] = this.baz); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-array-pattern/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-array-pattern/options.json new file mode 100644 index 000000000000..eb9bd0d7e9c5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-array-pattern/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Decorated private methods are read-only, but \"#x\" is updated via this expression." +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-for-of/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-for-of/input.js new file mode 100644 index 000000000000..2ffabb75d901 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-for-of/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec #x() {} + + bar() { + for (this.#x of this.baz); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-for-of/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-for-of/options.json new file mode 100644 index 000000000000..eb9bd0d7e9c5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-for-of/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Decorated private methods are read-only, but \"#x\" is updated via this expression." +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-object-pattern/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-object-pattern/input.js new file mode 100644 index 000000000000..a60de2bae344 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-object-pattern/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec #x() {} + + bar() { + ({ x: this.#x } = this.baz); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-object-pattern/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-object-pattern/options.json new file mode 100644 index 000000000000..eb9bd0d7e9c5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-object-pattern/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Decorated private methods are read-only, but \"#x\" is updated via this expression." +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-rest/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-rest/input.js new file mode 100644 index 000000000000..6b513a380627 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-rest/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec #x() {} + + bar() { + ([...this.#x] = this.baz); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-rest/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-rest/options.json new file mode 100644 index 000000000000..eb9bd0d7e9c5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-rest/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Decorated private methods are read-only, but \"#x\" is updated via this expression." +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-update/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-update/input.js new file mode 100644 index 000000000000..7d01837e1b51 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-update/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec #x() {} + + bar() { + this.#x++; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-update/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-update/options.json new file mode 100644 index 000000000000..eb9bd0d7e9c5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method-via-update/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Decorated private methods are read-only, but \"#x\" is updated via this expression." +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method/input.js new file mode 100644 index 000000000000..b6417214fec7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method/input.js @@ -0,0 +1,8 @@ +const dec = () => {}; +class Foo { + @dec #x() {} + + bar() { + this.#x = 123; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method/options.json new file mode 100644 index 000000000000..eb9bd0d7e9c5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-private-method/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Decorated private methods are read-only, but \"#x\" is updated via this expression." +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-shadowed-private-method-valid/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-shadowed-private-method-valid/input.js new file mode 100644 index 000000000000..66f4c182c2fc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-shadowed-private-method-valid/input.js @@ -0,0 +1,11 @@ +const dec = () => {}; +class Foo { + @dec #x() { + class Nested { + static #x; + static set x(v) { + this.#x = v; + } + } + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-shadowed-private-method-valid/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-shadowed-private-method-valid/output.js new file mode 100644 index 000000000000..f0feddfef3c4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/setting-shadowed-private-method-valid/output.js @@ -0,0 +1,18 @@ +let _initProto, _call_x; +const dec = () => {}; +class Foo { + static { + [_call_x, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "x", function () { + class Nested { + static #x; + static set x(v) { + this.#x = v; + } + } + }]], 0, _ => #x in _).e; + } + constructor() { + _initProto(this); + } + #x = _call_x; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-decorator/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-decorator/input.js new file mode 100644 index 000000000000..7e75b7766176 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-decorator/input.js @@ -0,0 +1,9 @@ +class A extends B { + m() { + @(super.dec1) + class C { + @(super.dec2) + m2() {} + } + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-decorator/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-decorator/output.js new file mode 100644 index 000000000000..a27046288262 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-decorator/output.js @@ -0,0 +1,22 @@ +class A extends B { + m() { + let _initProto, _initClass, _classDecs, _m2Decs; + _classDecs = [this, super.dec1]; + let _C; + class C { + static { + ({ + e: [_initProto], + c: [_C, _initClass] + } = babelHelpers.applyDecs2311(this, _classDecs, [[_m2Decs, 18, "m2"]], 1)); + } + constructor() { + _initProto(this); + } + [(_m2Decs = [this, super.dec2], "m2")]() {} + static { + _initClass(); + } + } + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-nested-constructor-expression/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-nested-constructor-expression/input.js similarity index 100% rename from crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-nested-constructor-expression/input.js rename to crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-nested-constructor-expression/input.js diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-nested-constructor-expression/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-nested-constructor-expression/output.js new file mode 100644 index 000000000000..b21f773187f3 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-nested-constructor-expression/output.js @@ -0,0 +1,15 @@ +var _Bar; +let _initClass; +const dec = () => {}; +let _Foo; +class Foo extends (_Bar = Bar) { + static { + [_Foo, _initClass] = babelHelpers.applyDecs2311(this, [dec], [], 0, void 0, _Bar).c; + } + constructor() { + let foo = super(); + } + static { + _initClass(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-accessor/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-accessor/input.js similarity index 100% rename from crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-accessor/input.js rename to crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-accessor/input.js diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-accessor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-accessor/output.js new file mode 100644 index 000000000000..f8d80dc189ec --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-accessor/output.js @@ -0,0 +1,17 @@ +var _Bar; +let _initProto, _call_x; +const dec = () => {}; +class Foo extends (_Bar = Bar) { + static { + [_call_x, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 3, "x", function () { + return babelHelpers.superPropGet(Foo, "foo", this, 2)([]); + }]], 0, _ => #x in _, _Bar).e; + } + constructor(...args) { + super(...args); + _initProto(this); + } + get #x() { + return _call_x(this); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-method/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-method/input.js similarity index 100% rename from crates/swc_ecma_transforms_proposal/tests/decorators/.2022-03-assumption-constantSuper/super-in-private-method/input.js rename to crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-method/input.js diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-method/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-method/output.js new file mode 100644 index 000000000000..c7ffd1c636d2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-method/output.js @@ -0,0 +1,15 @@ +var _Bar; +let _initProto, _call_x; +const dec = () => {}; +class Foo extends (_Bar = Bar) { + static { + [_call_x, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 2, "x", function () { + return babelHelpers.superPropGet(Foo, "foo", this, 2)([]); + }]], 0, _ => #x in _, _Bar).e; + } + constructor(...args) { + super(...args); + _initProto(this); + } + #x = _call_x; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/symbol-key/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/symbol-key/input.js new file mode 100644 index 000000000000..38d2b6c12192 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/symbol-key/input.js @@ -0,0 +1,9 @@ +let dec1, dec2, dec3; + +@dec1 +class A { + [notSymbol()] = 1; + @dec2 [Symbol.iterator] = 2; + [Symbol.for("foo")] = 3; + @dec3 [notSymbolAgain()] = 4; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/symbol-key/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/symbol-key/output.js new file mode 100644 index 000000000000..6a41f8424768 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/symbol-key/output.js @@ -0,0 +1,21 @@ +let _initClass, _computedKey, _init_computedKey, _init_extra_computedKey, _computedKey2, _init_computedKey2, _init_extra_computedKey2; +let dec1, dec2, dec3; +let _A; +class A { + static { + ({ + e: [_init_computedKey, _init_extra_computedKey, _init_computedKey2, _init_extra_computedKey2], + c: [_A, _initClass] + } = babelHelpers.applyDecs2311(this, [dec1], [[dec2, 0, Symbol.iterator], [dec3, 0, _computedKey2]])); + } + constructor() { + _init_extra_computedKey2(this); + } + [_computedKey = notSymbol()] = 1; + [Symbol.iterator] = _init_computedKey(this, 2); + [Symbol.for("foo")] = (_init_extra_computedKey(this), 3); + [_computedKey2 = babelHelpers.toPropertyKey(notSymbolAgain())] = _init_computedKey2(this, 4); + static { + _initClass(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/exec.js new file mode 100644 index 000000000000..a9b29f17b7bf --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/exec.js @@ -0,0 +1,31 @@ +"use strict"; + +let _this = []; + +function dec() { + _this.push(this); +} + +let o1 = { dec }; +let o2 = { dec }; +let o3 = { o: { dec } }; +let o4oCounter = 0; +let o4 = { o() { o4oCounter++; return o1 } }; + +@o1.dec +@dec +@o2.dec +@(o4.o().dec) +class A { + @o2.dec + @o3.o.dec + @(o4.o().dec) + x; + + @o2.dec + @dec + y; +} + +expect(_this).toEqual([o1, o3.o, o2, undefined, o2, o1, o2, undefined, o1]); +expect(o4oCounter).toBe(2); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/input.js new file mode 100644 index 000000000000..117148930d92 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/input.js @@ -0,0 +1,14 @@ +@o1.dec +@dec +@o2.dec +@(o4.o().dec) +class A { + @o2.dec + @o3.o.dec + @(o4.o().dec) + x; + + @o2.dec + @dec + y; +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/output.js new file mode 100644 index 000000000000..df39511cf848 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/this/output.js @@ -0,0 +1,18 @@ +let _initClass, _obj, _init_x, _init_extra_x, _init_y, _init_extra_y; +let _A; +class A { + static { + ({ + e: [_init_x, _init_extra_x, _init_y, _init_extra_y], + c: [_A, _initClass] + } = babelHelpers.applyDecs2311(this, [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec, _obj = o4.o(), _obj.dec], [[[_obj = o2, _obj.dec, _obj = o3.o, _obj.dec, _obj = o4.o(), _obj.dec], 16, "x"], [[_obj = o2, _obj.dec, void 0, dec], 16, "y"]], 1)); + } + constructor() { + _init_extra_y(this); + } + x = _init_x(this); + y = (_init_extra_x(this), _init_y(this)); + static { + _initClass(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/valid-expression-formats/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/valid-expression-formats/input.js new file mode 100644 index 000000000000..586564c5e219 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/valid-expression-formats/input.js @@ -0,0 +1,23 @@ +const dec = () => {}; +@dec +@call() +@chain.expr() +@(arbitrary + expr) +@(array[expr]) +class Foo { + #a; + + @dec + @call() + @chain.expr() + @(arbitrary + expr) + @(array[expr]) + method() {} + + makeClass() { + return class Nested { + @(this.#a) + bar; + } + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/valid-expression-formats/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/valid-expression-formats/output.js new file mode 100644 index 000000000000..659e76d1d7ba --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/valid-expression-formats/output.js @@ -0,0 +1,28 @@ +let _initProto, _initClass, _obj; +const dec = () => {}; +let _Foo; +class Foo { + static { + ({ + e: [_initProto], + c: [_Foo, _initClass] + } = babelHelpers.applyDecs2311(this, [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]], [[[void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]], 18, "method"]], 1)); + } + #a = void _initProto(this); + method() {} + makeClass() { + let _barDecs, _init_bar, _init_extra_bar; + return class Nested { + static { + [_init_bar, _init_extra_bar] = babelHelpers.applyDecs2311(this, [], [[_barDecs, 16, "bar"]]).e; + } + constructor() { + _init_extra_bar(this); + } + [(_barDecs = [this, this.#a], "bar")] = _init_bar(this); + }; + } + static { + _initClass(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-initializers-fields/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-initializers-fields/exec.js new file mode 100644 index 000000000000..d5b5a3d727e5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-initializers-fields/exec.js @@ -0,0 +1,67 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + }; + }; +} + +function logFieldDecoratorRun(a, b) { + push(a); + return function (el) { push(b); return el; }; +} + +@logClassDecoratorRun(0, 19, 21) +@logClassDecoratorRun(1, 18, 20) +class A { + @logAccessorDecoratorRun(2, 11, 25, 22) + @logAccessorDecoratorRun(3, 10, 24, 23) + accessor a; + + @logFieldDecoratorRun(4, 15) + @logFieldDecoratorRun(5, 14) + b; + + @logFieldDecoratorRun(6, 17) + @logFieldDecoratorRun(7, 16) + #c; + + @logAccessorDecoratorRun(8, 13, 29, 26) + @logAccessorDecoratorRun(9, 12, 28, 27) + accessor #d; + + constructor() { + this.a = this.#d = null; + } +} + +var nums = Array.from({ length: 22 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-initializers-setters/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-initializers-setters/exec.js new file mode 100644 index 000000000000..5d3b0a22baf5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-initializers-setters/exec.js @@ -0,0 +1,61 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d, e, f) { + push(a); + return function ({ set }, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + set(v) { push(e); const result = set.call(this, v); push(f); return result; } + }; + }; +} + +function logFieldDecoratorRun(a, b) { + push(a); + return function (el) { push(b); return el; }; +} + +@logClassDecoratorRun(0, 11, 13) +@logClassDecoratorRun(1, 10, 12) +class A { + @logAccessorDecoratorRun(2, 7, 17, 14, 22, 25) + @logAccessorDecoratorRun(3, 6, 16, 15, 23, 24) + accessor a; + + @logAccessorDecoratorRun(4, 9, 21, 18, 26, 29) + @logAccessorDecoratorRun(5, 8, 20, 19, 27, 28) + accessor #b; + + constructor() { + this.a = null; + this.#b = null; + } +} + +var nums = Array.from({ length: 14 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-method-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-method-initializers/exec.js new file mode 100644 index 000000000000..0b1103df2b78 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-method-initializers/exec.js @@ -0,0 +1,75 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + }; + }; +} + +function logMethodDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return () => (el(), push(d)) + }; +} + +@logClassDecoratorRun(0, 19, 21) +@logClassDecoratorRun(1, 18, 20) +class A { + @logAccessorDecoratorRun(2, 11, 29, 26) + @logAccessorDecoratorRun(3, 10, 28, 27) + accessor a; + + @logMethodDecoratorRun(4, 13, 23, 35) + @logMethodDecoratorRun(5, 12, 22, 34) + b() {}; + + @logMethodDecoratorRun(6, 15, 25, 37) + @logMethodDecoratorRun(7, 14, 24, 36) + #c() {}; + + @logAccessorDecoratorRun(8, 17, 33, 30) + @logAccessorDecoratorRun(9, 16, 32, 31) + accessor #d; + + constructor() { + this.b(); + this.#c(); + this.a = this.#d = null; + } +} + +var nums = Array.from({ length: 22 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 38 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-static-accessor-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-static-accessor-initializers/exec.js new file mode 100644 index 000000000000..03b152794d4a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-static-accessor-initializers/exec.js @@ -0,0 +1,51 @@ +var log = []; + +function push(x) { log.push(x); return x; } + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { push(c); }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { push(c); }); + return { + init: () => push(d) + }; + }; +} + +@logClassDecoratorRun(0, 19, 29) +@logClassDecoratorRun(1, 18, 28) +class A { + @logAccessorDecoratorRun(2, 15, 33, 30) + @logAccessorDecoratorRun(3, 14, 32, 31) + accessor a; + + @logAccessorDecoratorRun(4, 11, 23, 20) + @logAccessorDecoratorRun(5, 10, 22, 21) + static accessor b; + + @logAccessorDecoratorRun(6, 13, 27, 24) + @logAccessorDecoratorRun(7, 12, 26, 25) + static accessor #c; + + @logAccessorDecoratorRun(8, 17, 37, 34) + @logAccessorDecoratorRun(9, 16, 36, 35) + accessor #d; +} + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 38 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-static-method-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-static-method-initializers/exec.js new file mode 100644 index 000000000000..441c746d4d42 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/accessor-static-method-initializers/exec.js @@ -0,0 +1,77 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + }; + }; +} + +function logMethodDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return () => (el(), push(d)) + }; +} + +@logClassDecoratorRun(0, 19, 29) +@logClassDecoratorRun(1, 18, 28) +class A { + static { + A.b(), A.#c(); + } + + @logAccessorDecoratorRun(2, 15, 33, 30) + @logAccessorDecoratorRun(3, 14, 32, 31) + accessor a; + + @logMethodDecoratorRun(4, 11, 21, 25) + @logMethodDecoratorRun(5, 10, 20, 24) + static b() {}; + + @logMethodDecoratorRun(6, 13, 23, 27) + @logMethodDecoratorRun(7, 12, 22, 26) + static #c() {}; + + @logAccessorDecoratorRun(8, 17, 37, 34) + @logAccessorDecoratorRun(9, 16, 36, 35) + accessor #d; + + constructor() { + this.a = this.#d = null; + } +} + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 38 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/exec.js new file mode 100644 index 000000000000..8f39f3ddf6e8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/exec.js @@ -0,0 +1,118 @@ +const classDec1 = (log) => (cls, ctxClass) => { + log.push("c2"); + ctxClass.addInitializer(() => log.push("c5")); + ctxClass.addInitializer(() => log.push("c6")); +}; +const classDec2 = (log) => (cls, ctxClass) => { + log.push("c1"); + ctxClass.addInitializer(() => log.push("c3")); + ctxClass.addInitializer(() => log.push("c4")); +}; + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + [log.push("k1")]; + [log.push("k2")]; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static [log.push("k1")]; + async [log.push("k2")](v) {}; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + get [log.push("k1")]() {}; + static [log.push("k2")]; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + [log.push("k1")]; + accessor [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static set [log.push("k1")](v) {}; + [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static [log.push("k1")]; + static [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/input.js new file mode 100644 index 000000000000..8f39f3ddf6e8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/input.js @@ -0,0 +1,118 @@ +const classDec1 = (log) => (cls, ctxClass) => { + log.push("c2"); + ctxClass.addInitializer(() => log.push("c5")); + ctxClass.addInitializer(() => log.push("c6")); +}; +const classDec2 = (log) => (cls, ctxClass) => { + log.push("c1"); + ctxClass.addInitializer(() => log.push("c3")); + ctxClass.addInitializer(() => log.push("c4")); +}; + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + [log.push("k1")]; + [log.push("k2")]; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static [log.push("k1")]; + async [log.push("k2")](v) {}; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + get [log.push("k1")]() {}; + static [log.push("k2")]; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + [log.push("k1")]; + accessor [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static set [log.push("k1")](v) {}; + [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static [log.push("k1")]; + static [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/options.json new file mode 100644 index 000000000000..6386e25ffdf6 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "7.6.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/output.js new file mode 100644 index 000000000000..e36651340180 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/class-decorators-without-element-decorators/output.js @@ -0,0 +1,155 @@ +const classDec1 = log => (cls, ctxClass) => { + log.push("c2"); + ctxClass.addInitializer(() => log.push("c5")); + ctxClass.addInitializer(() => log.push("c6")); +}; +const classDec2 = log => (cls, ctxClass) => { + log.push("c1"); + ctxClass.addInitializer(() => log.push("c3")); + ctxClass.addInitializer(() => log.push("c4")); +}; +{ + var _C2; + let _initClass, _classDecs, _log$push, _log$push2, _log$push3; + const log = []; + _classDecs = [classDec1(log), classDec2(log)]; + let _C; + _log$push = log.push("k1"); + _log$push2 = log.push("k2"); + _log$push3 = log.push("k3"); + class C { + constructor() { + babelHelpers.defineProperty(this, _log$push, void 0); + babelHelpers.defineProperty(this, _log$push2, void 0); + babelHelpers.defineProperty(this, _log$push3, void 0); + } + } + _C2 = C; + [_C, _initClass] = babelHelpers.applyDecs2311(_C2, _classDecs, []).c; + _initClass(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + var _Class, _C5; + let _initClass2, _classDecs2, _computedKey, _C4, _ref, _log$push4; + const log = []; + _classDecs2 = [classDec1(log), classDec2(log)]; + let _C3; + new (_C4 = (_ref = (_computedKey = log.push("k1"), log.push("k2")), _log$push4 = log.push("k3"), _C5 = class C { + constructor() { + babelHelpers.defineProperty(this, _log$push4, void 0); + } + async [_ref](v) {} + }, [_C3, _initClass2] = babelHelpers.applyDecs2311(_C5, _classDecs2, []).c, _C5), _Class = class extends babelHelpers.identity { + constructor() { + super(_C3), babelHelpers.defineProperty(this, _computedKey, void 0), _initClass2(); + } + }, babelHelpers.defineProperty(_Class, _C4, void 0), _Class)(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + var _Class2, _C8; + let _initClass3, _classDecs3, _computedKey3, _C7, _log$push5, _ref2; + const log = []; + _classDecs3 = [classDec1(log), classDec2(log)]; + let _C6; + new (_C7 = (_log$push5 = log.push("k1"), _ref2 = (_computedKey3 = log.push("k2"), log.push("k3")), _C8 = class C { + constructor() { + babelHelpers.defineProperty(this, _ref2, void 0); + } + get [_log$push5]() {} + }, [_C6, _initClass3] = babelHelpers.applyDecs2311(_C8, _classDecs3, []).c, _C8), _Class2 = class extends babelHelpers.identity { + constructor() { + super(_C6), babelHelpers.defineProperty(this, _computedKey3, void 0), _initClass3(); + } + }, babelHelpers.defineProperty(_Class2, _C7, void 0), _Class2)(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + var _Class3, _C11, _A; + let _computedKey5, _initClass4, _classDecs4, _computedKey6, _C10, _log$push6, _ref3; + const log = []; + _classDecs4 = [classDec1(log), classDec2(log)]; + let _C9; + new (_C10 = (_A = /*#__PURE__*/new WeakMap(), _log$push6 = log.push("k1"), _computedKey5 = babelHelpers.toPropertyKey(log.push("k2")), _ref3 = (_computedKey6 = log.push("k3"), _computedKey5), _C11 = class C { + constructor() { + babelHelpers.defineProperty(this, _log$push6, void 0); + babelHelpers.classPrivateFieldInitSpec(this, _A, void 0); + } + get [_computedKey5]() { + return babelHelpers.classPrivateFieldGet2(_A, this); + } + set [_ref3](v) { + babelHelpers.classPrivateFieldSet2(_A, this, v); + } + }, [_C9, _initClass4] = babelHelpers.applyDecs2311(_C11, _classDecs4, []).c, _C11), _Class3 = class extends babelHelpers.identity { + constructor() { + super(_C9), babelHelpers.defineProperty(this, _computedKey6, void 0), _initClass4(); + } + }, babelHelpers.defineProperty(_Class3, _C10, void 0), _Class3)(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + var _Class4, _C14; + let _initClass5, _classDecs5, _computedKey10, _computedKey11, _C13, _log$push7, _ref4; + const log = []; + _classDecs5 = [classDec1(log), classDec2(log)]; + let _C12; + new (_C13 = (_log$push7 = log.push("k1"), _ref4 = (_computedKey11 = log.push("k2"), _computedKey10 = log.push("k3"), _computedKey11), _C14 = class C { + constructor() { + babelHelpers.defineProperty(this, _ref4, void 0); + } + static set [_log$push7](v) {} + }, [_C12, _initClass5] = babelHelpers.applyDecs2311(_C14, _classDecs5, []).c, _C14), _Class4 = class extends babelHelpers.identity { + constructor() { + super(_C12), babelHelpers.defineProperty(this, _computedKey10, void 0), _initClass5(); + } + }, babelHelpers.defineProperty(_Class4, _C13, void 0), _Class4)(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + var _Class5, _C17; + let _initClass6, _classDecs6, _computedKey13, _computedKey14, _computedKey15, _C16, _ref5; + const log = []; + _classDecs6 = [classDec1(log), classDec2(log)]; + let _C15; + new (_C16 = (_ref5 = (_computedKey13 = log.push("k1"), _computedKey14 = log.push("k2"), _computedKey15 = log.push("k3"), "_"), _C17 = class C {}, babelHelpers.defineProperty(_C17, _ref5, void 0), (() => { + delete _C17._; + [_C15, _initClass6] = babelHelpers.applyDecs2311(_C17, _classDecs6, []).c; + })(), _C17), _Class5 = class extends babelHelpers.identity { + constructor() { + super(_C15), babelHelpers.defineProperty(this, _computedKey13, void 0), babelHelpers.defineProperty(this, _computedKey14, void 0), babelHelpers.defineProperty(this, _computedKey15, void 0), _initClass6(); + } + }, babelHelpers.defineProperty(_Class5, _C16, void 0), _Class5)(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/decorators-evaluation-with-this-caching/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/decorators-evaluation-with-this-caching/exec.js new file mode 100644 index 000000000000..58db24bae6d8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/decorators-evaluation-with-this-caching/exec.js @@ -0,0 +1,17 @@ +let result = []; +const fn = () => { result.push(1); return () => {} } +const obj = { + get prop() { + result.push(2); + return { + get foo() { result.push(3); return () => {} } + } + } +}; +class A { + @fn() + @obj.prop.foo + method() {} +} + +expect(result).toEqual([1, 2, 3]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/decorators-evaluation-with-this-caching/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/decorators-evaluation-with-this-caching/input.js new file mode 100644 index 000000000000..819f9050333d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/decorators-evaluation-with-this-caching/input.js @@ -0,0 +1,7 @@ +let fn, obj; +class A { + @fn() + @obj.prop.foo + method() {} +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/decorators-evaluation-with-this-caching/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/decorators-evaluation-with-this-caching/output.js new file mode 100644 index 000000000000..f07fb45227e9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/decorators-evaluation-with-this-caching/output.js @@ -0,0 +1,11 @@ +var _A; +let _initProto, _obj; +let fn, obj; +class A { + constructor() { + _initProto(this); + } + method() {} +} +_A = A; +[_initProto] = babelHelpers.applyDecs2311(_A, [], [[[void 0, fn(), _obj = obj.prop, _obj.foo], 18, "method"]]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/field-initializers-after-methods/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/field-initializers-after-methods/exec.js new file mode 100644 index 000000000000..46e71f7281db --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/field-initializers-after-methods/exec.js @@ -0,0 +1,27 @@ +var counter = 0; + +@(x => x) +class A { + foo = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.foo).toBeUndefined(); + expect(this.bar).toBeUndefined(); + return "foo"; + })(); + + method() {} + + bar = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.foo).toBe("foo"); + expect(this.bar).toBeUndefined(); + })(); +} + +expect(counter).toBe(0); + +new A(); + +expect(counter).toBe(2); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/field/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/field/exec.js new file mode 100644 index 000000000000..7a51e8b93b7e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/field/exec.js @@ -0,0 +1,31 @@ +var log = []; + +function push(x) { log.push(x); return x; } + +function logDecoratorRun(a, b) { + push(a); + return function (el) { push(b); return el; }; +} + +@logDecoratorRun(0, 21) +@logDecoratorRun(1, 20) +class A { + @logDecoratorRun(2, 17) + @logDecoratorRun(3, 16) + [push(4)]; + + @logDecoratorRun(5, 13) + @logDecoratorRun(6, 12) + static [push(7)]; + + @logDecoratorRun(8, 15) + @logDecoratorRun(9, 14) + static #c; + + @logDecoratorRun(10, 19) + @logDecoratorRun(11, 18) + #d; +} + +var nums = Array.from({ length: 22 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/initializers-and-static-blocks/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/initializers-and-static-blocks/exec.js new file mode 100644 index 000000000000..b3ef6feb24bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/initializers-and-static-blocks/exec.js @@ -0,0 +1,217 @@ +const log = []; +const classDec1 = (cls, ctxClass) => { + log.push("c2"); + ctxClass.addInitializer(() => log.push("c5")); + ctxClass.addInitializer(() => log.push("c6")); +}; +const classDec2 = (cls, ctxClass) => { + log.push("c1"); + ctxClass.addInitializer(() => log.push("c3")); + ctxClass.addInitializer(() => log.push("c4")); +}; +const methodDec1 = (fn, ctxMethod) => { + log.push("m2"); + ctxMethod.addInitializer(() => log.push("m5")); + ctxMethod.addInitializer(() => log.push("m6")); +}; +const methodDec2 = (fn, ctxMethod) => { + log.push("m1"); + ctxMethod.addInitializer(() => log.push("m3")); + ctxMethod.addInitializer(() => log.push("m4")); +}; +const staticMethodDec1 = (fn, ctxStaticMethod) => { + log.push("M2"); + ctxStaticMethod.addInitializer(() => log.push("M5")); + ctxStaticMethod.addInitializer(() => log.push("M6")); +}; +const staticMethodDec2 = (fn, ctxStaticMethod) => { + log.push("M1"); + ctxStaticMethod.addInitializer(() => log.push("M3")); + ctxStaticMethod.addInitializer(() => log.push("M4")); +}; +const fieldDec1 = (value, ctxField) => { + log.push("f2"); + ctxField.addInitializer(() => log.push("f7")); + ctxField.addInitializer(() => log.push("f8")); + return () => { + log.push("f3"); + }; +}; +const fieldDec2 = (value, ctxField) => { + log.push("f1"); + ctxField.addInitializer(() => log.push("f5")); + ctxField.addInitializer(() => log.push("f6")); + return () => { + log.push("f4"); + }; +}; +const staticFieldDec1 = (value, ctxStaticField) => { + log.push("F2"); + ctxStaticField.addInitializer(() => log.push("F7")); + ctxStaticField.addInitializer(() => log.push("F8")); + return () => { + log.push("F3"); + }; +}; +const staticFieldDec2 = (value, ctxStaticField) => { + log.push("F1"); + ctxStaticField.addInitializer(() => log.push("F5")); + ctxStaticField.addInitializer(() => log.push("F6")); + return () => { + log.push("F4"); + }; +}; +const getterDec1 = (fn, ctxGetter) => { + log.push("g2"); + ctxGetter.addInitializer(() => log.push("g5")); + ctxGetter.addInitializer(() => log.push("g6")); +}; +const getterDec2 = (fn, ctxGetter) => { + log.push("g1"); + ctxGetter.addInitializer(() => log.push("g3")); + ctxGetter.addInitializer(() => log.push("g4")); +}; +const staticGetterDec1 = (fn, ctxStaticGetter) => { + log.push("G2"); + ctxStaticGetter.addInitializer(() => log.push("G5")); + ctxStaticGetter.addInitializer(() => log.push("G6")); +}; +const staticGetterDec2 = (fn, ctxStaticGetter) => { + log.push("G1"); + ctxStaticGetter.addInitializer(() => log.push("G3")); + ctxStaticGetter.addInitializer(() => log.push("G4")); +}; +const setterDec1 = (fn, ctxSetter) => { + log.push("s2"); + ctxSetter.addInitializer(() => log.push("s5")); + ctxSetter.addInitializer(() => log.push("s6")); +}; +const setterDec2 = (fn, ctxSetter) => { + log.push("s1"); + ctxSetter.addInitializer(() => log.push("s3")); + ctxSetter.addInitializer(() => log.push("s4")); +}; +const staticSetterDec1 = (fn, ctxStaticSetter) => { + log.push("S2"); + ctxStaticSetter.addInitializer(() => log.push("S5")); + ctxStaticSetter.addInitializer(() => log.push("S6")); +}; +const staticSetterDec2 = (fn, ctxStaticSetter) => { + log.push("S1"); + ctxStaticSetter.addInitializer(() => log.push("S3")); + ctxStaticSetter.addInitializer(() => log.push("S4")); +}; +const accessorDec1 = (target, ctxAccessor) => { + log.push("a2"); + ctxAccessor.addInitializer(() => log.push("a7")); + ctxAccessor.addInitializer(() => log.push("a8")); + return { init() { + log.push("a3"); + } }; +}; +const accessorDec2 = (target, ctxAccessor) => { + log.push("a1"); + ctxAccessor.addInitializer(() => log.push("a5")); + ctxAccessor.addInitializer(() => log.push("a6")); + return { init() { + log.push("a4"); + } }; +}; +const staticAccessorDec1 = (target, ctxStaticAccessor) => { + log.push("A2"); + ctxStaticAccessor.addInitializer(() => log.push("A7")); + ctxStaticAccessor.addInitializer(() => log.push("A8")); + return { init() { + log.push("A3"); + } }; +}; +const staticAccessorDec2 = (target, ctxStaticAccessor) => { + log.push("A1"); + ctxStaticAccessor.addInitializer(() => log.push("A5")); + ctxStaticAccessor.addInitializer(() => log.push("A6")); + return { init() { + log.push("A4"); + } }; +}; +log.push("start"); +@classDec1 +@classDec2 +class Foo extends (log.push("extends"), Object) { + static { + log.push("static:start"); + } + constructor() { + log.push("ctor:start"); + super(); + log.push("ctor:end"); + } + @methodDec1 + @methodDec2 + method() { + } + @staticMethodDec1 + @staticMethodDec2 + static method() { + } + @fieldDec1 + @fieldDec2 + field; + @staticFieldDec1 + @staticFieldDec2 + static field; + @getterDec1 + @getterDec2 + get getter() { + return; + } + @staticGetterDec1 + @staticGetterDec2 + static get getter() { + return; + } + @setterDec1 + @setterDec2 + set setter(x) { + } + @staticSetterDec1 + @staticSetterDec2 + static set getter(x) { + } + @accessorDec1 + @accessorDec2 + accessor accessor; + @staticAccessorDec1 + @staticAccessorDec2 + static accessor accessor; + static { + log.push("static:end"); + } +} +log.push("after"); +new Foo(); +log.push("end"); +expect(log + "").toEqual( + 'start,extends,' + + 'M1,M2,G1,G2,S1,S2,A1,A2,' + // For each element e of staticElements if e.[[Kind]] is not field + 'm1,m2,g1,g2,s1,s2,a1,a2,' + // For each element e of instanceElements if e.[[Kind]] is not field + 'F1,F2,' + // For each element e of staticElements if e.[[Kind]] is field + 'f1,f2,' + // For each element e of instanceElements if e.[[Kind]] is field + 'c1,c2,' + // ApplyDecoratorsToClassDefinition + 'M3,M4,M5,M6,G3,G4,G5,G6,S3,S4,S5,S6,' + // staticExtraInitializers + 'static:start,' + // staticElements + 'F3,F4,' + // InitializeFieldOrAccessor + 'F5,F6,F7,F8,' + // field extraInitializers + 'A3,A4,' + // InitializeFieldOrAccessor + 'A5,A6,A7,A8,' + // accessor extraInitializers + 'static:end,' + // staticElements + 'c3,c4,c5,c6,' + // classExtraInitializers + 'after,' + + 'ctor:start,' + + 'm3,m4,m5,m6,g3,g4,g5,g6,s3,s4,s5,s6,' + // instanceExtraInitializers + 'f3,f4,' + // InitializeFieldOrAccessor + 'f5,f6,f7,f8,' + // field extraInitializers + 'a3,a4,' + // InitializeFieldOrAccessor + 'a5,a6,a7,a8,' + // field extraInitializers + 'ctor:end,' + + 'end' +); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/initializers/exec.js new file mode 100644 index 000000000000..2a43cb651ee9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/initializers/exec.js @@ -0,0 +1,56 @@ +var log = []; + +function push(x) { log.push(x); return x; } + +function logDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { push(c); }); + return el; + }; +} + +@logDecoratorRun(0, 35, 45) +@logDecoratorRun(1, 34, 44) +class A { + @logDecoratorRun(2, 27, 47) + @logDecoratorRun(3, 26, 46) + a() {}; + + @logDecoratorRun(4, 19, 37) + @logDecoratorRun(5, 18, 36) + static b() {}; + + @logDecoratorRun(6, 21, 39) + @logDecoratorRun(7, 20, 38) + static #c() {}; + + @logDecoratorRun(8, 29, 49) + @logDecoratorRun(9, 28, 48) + #d() {}; + + @logDecoratorRun(10, 31, 51) + @logDecoratorRun(11, 30, 50) + accessor e; + + @logDecoratorRun(12, 23, 41) + @logDecoratorRun(13, 22, 40) + static accessor f; + + @logDecoratorRun(14, 25, 43) + @logDecoratorRun(15, 24, 42) + static accessor #g; + + @logDecoratorRun(16, 33, 53) + @logDecoratorRun(17, 32, 52) + accessor #h; +} + +var nums = Array.from({ length: 46 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 54 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/method-initializers-field-value/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/method-initializers-field-value/exec.js new file mode 100644 index 000000000000..c1aacb35624e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/method-initializers-field-value/exec.js @@ -0,0 +1,153 @@ +{ + const log = []; + const methodDec1 = (fn, ctxMethod) => { + log.push("m2"); + ctxMethod.addInitializer(() => log.push("m5")); + ctxMethod.addInitializer(() => log.push("m6")); + }; + const methodDec2 = (fn, ctxMethod) => { + log.push("m1"); + ctxMethod.addInitializer(() => log.push("m3")); + ctxMethod.addInitializer(() => log.push("m4")); + }; + const getterDec1 = (fn, ctxGetter) => { + log.push("g2"); + ctxGetter.addInitializer(() => log.push("g5")); + ctxGetter.addInitializer(() => log.push("g6")); + }; + const getterDec2 = (fn, ctxGetter) => { + log.push("g1"); + ctxGetter.addInitializer(() => log.push("g3")); + ctxGetter.addInitializer(() => log.push("g4")); + }; + const setterDec1 = (fn, ctxSetter) => { + log.push("s2"); + ctxSetter.addInitializer(() => log.push("s5")); + ctxSetter.addInitializer(() => log.push("s6")); + }; + const setterDec2 = (fn, ctxSetter) => { + log.push("s1"); + ctxSetter.addInitializer(() => log.push("s3")); + ctxSetter.addInitializer(() => log.push("s4")); + }; + log.push("start"); + class Foo extends (log.push("extends"), Object) { + static { + log.push("static:start"); + } + constructor() { + log.push("ctor:start"); + super(); + log.push("ctor:end"); + } + @methodDec1 + @methodDec2 + method() {} + + field = log.push("f"); + + @getterDec1 + @getterDec2 + get getter() { + return; + } + @setterDec1 + @setterDec2 + set setter(x) {} + static { + log.push("static:end"); + } + } + log.push("after"); + new Foo(); + log.push("end"); + expect(log + "").toEqual( + "start,extends," + + "m1,m2,g1,g2,s1,s2," + // For each element e of instanceElements if e.[[Kind]] is not field + "static:start," + // staticElements + "static:end," + // staticElements + "after," + + "ctor:start," + + "m3,m4,m5,m6,g3,g4,g5,g6,s3,s4,s5,s6," + // instanceExtraInitializers + "f," + // InitializeFieldOrAccessor + "ctor:end," + + "end", + ); +} + +{ + const log = []; + const methodDec1 = (fn, ctxMethod) => { + log.push("m2"); + ctxMethod.addInitializer(() => log.push("m5")); + ctxMethod.addInitializer(() => log.push("m6")); + }; + const methodDec2 = (fn, ctxMethod) => { + log.push("m1"); + ctxMethod.addInitializer(() => log.push("m3")); + ctxMethod.addInitializer(() => log.push("m4")); + }; + const getterDec1 = (fn, ctxGetter) => { + log.push("g2"); + ctxGetter.addInitializer(() => log.push("g5")); + ctxGetter.addInitializer(() => log.push("g6")); + }; + const getterDec2 = (fn, ctxGetter) => { + log.push("g1"); + ctxGetter.addInitializer(() => log.push("g3")); + ctxGetter.addInitializer(() => log.push("g4")); + }; + const setterDec1 = (fn, ctxSetter) => { + log.push("s2"); + ctxSetter.addInitializer(() => log.push("s5")); + ctxSetter.addInitializer(() => log.push("s6")); + }; + const setterDec2 = (fn, ctxSetter) => { + log.push("s1"); + ctxSetter.addInitializer(() => log.push("s3")); + ctxSetter.addInitializer(() => log.push("s4")); + }; + log.push("start"); + class Foo extends (log.push("extends"), Object) { + static { + log.push("static:start"); + } + constructor() { + log.push("ctor:start"); + super(); + log.push("ctor:end"); + } + @methodDec1 + @methodDec2 + method() {} + + accessor field = log.push("a"); + + @getterDec1 + @getterDec2 + get getter() { + return; + } + @setterDec1 + @setterDec2 + set setter(x) {} + static { + log.push("static:end"); + } + } + log.push("after"); + new Foo(); + log.push("end"); + expect(log + "").toEqual( + "start,extends," + + "m1,m2,g1,g2,s1,s2," + // For each element e of instanceElements if e.[[Kind]] is not field + "static:start," + // staticElements + "static:end," + // staticElements + "after," + + "ctor:start," + + "m3,m4,m5,m6,g3,g4,g5,g6,s3,s4,s5,s6," + // instanceExtraInitializers + "a," + // InitializeFieldOrAccessor + "ctor:end," + + "end", + ); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/static-accessor-method-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/static-accessor-method-initializers/exec.js new file mode 100644 index 000000000000..b776def232c5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/static-accessor-method-initializers/exec.js @@ -0,0 +1,74 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + }; + }; +} + +function logMethodDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return () => (el(), push(d)) + }; +} + +@logClassDecoratorRun(0, 19, 29) +@logClassDecoratorRun(1, 18, 28) +class A { + @logMethodDecoratorRun(2, 15, 31, 35) + @logMethodDecoratorRun(3, 14, 30, 34) + a() {} + + @logAccessorDecoratorRun(4, 11, 23, 20) + @logAccessorDecoratorRun(5, 10, 22, 21) + static accessor b; + + @logAccessorDecoratorRun(6, 13, 27, 24) + @logAccessorDecoratorRun(7, 12, 26, 25) + static accessor #c; + + @logMethodDecoratorRun(8, 17, 33, 37) + @logMethodDecoratorRun(9, 16, 32, 36) + #d() {} + + constructor() { + this.a(); + this.#d(); + } +} + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 38 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/static-field-initializers-after-methods/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/static-field-initializers-after-methods/exec.js new file mode 100644 index 000000000000..0703f091cc8d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering--to-es2015/static-field-initializers-after-methods/exec.js @@ -0,0 +1,23 @@ +var counter = 0; + +@(x => x) +class A { + static foo = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.foo).toBeUndefined(); + expect(this.bar).toBeUndefined(); + return "foo"; + })(); + + static method() {} + + static bar = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.foo).toBe("foo"); + expect(this.bar).toBeUndefined(); + })(); +} + +expect(counter).toBe(2); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-init-and-set-consistent/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-init-and-set-consistent/exec.js new file mode 100644 index 000000000000..468ab5d32fb1 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-init-and-set-consistent/exec.js @@ -0,0 +1,30 @@ +function minusTwo({ set }) { + return { + set(v) { + set.call(this, v - 2); + }, + init(v) { + return v - 2; + }, + }; +} + +function timesFour({ set }) { + return { + set(v) { + set.call(this, v * 4); + }, + init(v) { + return v * 4; + }, + }; +} + +class Foo { + @minusTwo @timesFour accessor bar = 5; +} +const foo = new Foo(); +expect(foo.bar).toBe(12); // (5 - 2) * 4 + +foo.bar = 5; +expect(foo.bar).toBe(12); // (5 - 2) * 4 diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-initializers-fields/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-initializers-fields/exec.js new file mode 100644 index 000000000000..d5b5a3d727e5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-initializers-fields/exec.js @@ -0,0 +1,67 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + }; + }; +} + +function logFieldDecoratorRun(a, b) { + push(a); + return function (el) { push(b); return el; }; +} + +@logClassDecoratorRun(0, 19, 21) +@logClassDecoratorRun(1, 18, 20) +class A { + @logAccessorDecoratorRun(2, 11, 25, 22) + @logAccessorDecoratorRun(3, 10, 24, 23) + accessor a; + + @logFieldDecoratorRun(4, 15) + @logFieldDecoratorRun(5, 14) + b; + + @logFieldDecoratorRun(6, 17) + @logFieldDecoratorRun(7, 16) + #c; + + @logAccessorDecoratorRun(8, 13, 29, 26) + @logAccessorDecoratorRun(9, 12, 28, 27) + accessor #d; + + constructor() { + this.a = this.#d = null; + } +} + +var nums = Array.from({ length: 22 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-initializers-setters/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-initializers-setters/exec.js new file mode 100644 index 000000000000..5d3b0a22baf5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-initializers-setters/exec.js @@ -0,0 +1,61 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d, e, f) { + push(a); + return function ({ set }, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + set(v) { push(e); const result = set.call(this, v); push(f); return result; } + }; + }; +} + +function logFieldDecoratorRun(a, b) { + push(a); + return function (el) { push(b); return el; }; +} + +@logClassDecoratorRun(0, 11, 13) +@logClassDecoratorRun(1, 10, 12) +class A { + @logAccessorDecoratorRun(2, 7, 17, 14, 22, 25) + @logAccessorDecoratorRun(3, 6, 16, 15, 23, 24) + accessor a; + + @logAccessorDecoratorRun(4, 9, 21, 18, 26, 29) + @logAccessorDecoratorRun(5, 8, 20, 19, 27, 28) + accessor #b; + + constructor() { + this.a = null; + this.#b = null; + } +} + +var nums = Array.from({ length: 14 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-method-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-method-initializers/exec.js new file mode 100644 index 000000000000..0b1103df2b78 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-method-initializers/exec.js @@ -0,0 +1,75 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + }; + }; +} + +function logMethodDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return () => (el(), push(d)) + }; +} + +@logClassDecoratorRun(0, 19, 21) +@logClassDecoratorRun(1, 18, 20) +class A { + @logAccessorDecoratorRun(2, 11, 29, 26) + @logAccessorDecoratorRun(3, 10, 28, 27) + accessor a; + + @logMethodDecoratorRun(4, 13, 23, 35) + @logMethodDecoratorRun(5, 12, 22, 34) + b() {}; + + @logMethodDecoratorRun(6, 15, 25, 37) + @logMethodDecoratorRun(7, 14, 24, 36) + #c() {}; + + @logAccessorDecoratorRun(8, 17, 33, 30) + @logAccessorDecoratorRun(9, 16, 32, 31) + accessor #d; + + constructor() { + this.b(); + this.#c(); + this.a = this.#d = null; + } +} + +var nums = Array.from({ length: 22 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 38 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-static-accessor-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-static-accessor-initializers/exec.js new file mode 100644 index 000000000000..03b152794d4a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-static-accessor-initializers/exec.js @@ -0,0 +1,51 @@ +var log = []; + +function push(x) { log.push(x); return x; } + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { push(c); }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { push(c); }); + return { + init: () => push(d) + }; + }; +} + +@logClassDecoratorRun(0, 19, 29) +@logClassDecoratorRun(1, 18, 28) +class A { + @logAccessorDecoratorRun(2, 15, 33, 30) + @logAccessorDecoratorRun(3, 14, 32, 31) + accessor a; + + @logAccessorDecoratorRun(4, 11, 23, 20) + @logAccessorDecoratorRun(5, 10, 22, 21) + static accessor b; + + @logAccessorDecoratorRun(6, 13, 27, 24) + @logAccessorDecoratorRun(7, 12, 26, 25) + static accessor #c; + + @logAccessorDecoratorRun(8, 17, 37, 34) + @logAccessorDecoratorRun(9, 16, 36, 35) + accessor #d; +} + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 38 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-static-method-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-static-method-initializers/exec.js new file mode 100644 index 000000000000..441c746d4d42 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/accessor-static-method-initializers/exec.js @@ -0,0 +1,77 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + }; + }; +} + +function logMethodDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return () => (el(), push(d)) + }; +} + +@logClassDecoratorRun(0, 19, 29) +@logClassDecoratorRun(1, 18, 28) +class A { + static { + A.b(), A.#c(); + } + + @logAccessorDecoratorRun(2, 15, 33, 30) + @logAccessorDecoratorRun(3, 14, 32, 31) + accessor a; + + @logMethodDecoratorRun(4, 11, 21, 25) + @logMethodDecoratorRun(5, 10, 20, 24) + static b() {}; + + @logMethodDecoratorRun(6, 13, 23, 27) + @logMethodDecoratorRun(7, 12, 22, 26) + static #c() {}; + + @logAccessorDecoratorRun(8, 17, 37, 34) + @logAccessorDecoratorRun(9, 16, 36, 35) + accessor #d; + + constructor() { + this.a = this.#d = null; + } +} + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 38 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/class-decorators-without-element-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/class-decorators-without-element-decorators/exec.js new file mode 100644 index 000000000000..8f39f3ddf6e8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/class-decorators-without-element-decorators/exec.js @@ -0,0 +1,118 @@ +const classDec1 = (log) => (cls, ctxClass) => { + log.push("c2"); + ctxClass.addInitializer(() => log.push("c5")); + ctxClass.addInitializer(() => log.push("c6")); +}; +const classDec2 = (log) => (cls, ctxClass) => { + log.push("c1"); + ctxClass.addInitializer(() => log.push("c3")); + ctxClass.addInitializer(() => log.push("c4")); +}; + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + [log.push("k1")]; + [log.push("k2")]; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static [log.push("k1")]; + async [log.push("k2")](v) {}; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + get [log.push("k1")]() {}; + static [log.push("k2")]; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + [log.push("k1")]; + accessor [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static set [log.push("k1")](v) {}; + [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static [log.push("k1")]; + static [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/class-decorators-without-element-decorators/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/class-decorators-without-element-decorators/input.js new file mode 100644 index 000000000000..8f39f3ddf6e8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/class-decorators-without-element-decorators/input.js @@ -0,0 +1,118 @@ +const classDec1 = (log) => (cls, ctxClass) => { + log.push("c2"); + ctxClass.addInitializer(() => log.push("c5")); + ctxClass.addInitializer(() => log.push("c6")); +}; +const classDec2 = (log) => (cls, ctxClass) => { + log.push("c1"); + ctxClass.addInitializer(() => log.push("c3")); + ctxClass.addInitializer(() => log.push("c4")); +}; + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + [log.push("k1")]; + [log.push("k2")]; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static [log.push("k1")]; + async [log.push("k2")](v) {}; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + get [log.push("k1")]() {}; + static [log.push("k2")]; + [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + [log.push("k1")]; + accessor [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static set [log.push("k1")](v) {}; + [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} + +{ + const log = []; + + @classDec1(log) + @classDec2(log) + class C { + static [log.push("k1")]; + static [log.push("k2")]; + static [log.push("k3")]; + } + + expect(log.join()).toBe( + "k1,k2,k3," + // ClassElementEvaluation + "c1,c2," + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6", // classExtraInitializers + ); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/class-decorators-without-element-decorators/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/class-decorators-without-element-decorators/output.js new file mode 100644 index 000000000000..9974c47f2451 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/class-decorators-without-element-decorators/output.js @@ -0,0 +1,166 @@ +const classDec1 = log => (cls, ctxClass) => { + log.push("c2"); + ctxClass.addInitializer(() => log.push("c5")); + ctxClass.addInitializer(() => log.push("c6")); +}; +const classDec2 = log => (cls, ctxClass) => { + log.push("c1"); + ctxClass.addInitializer(() => log.push("c3")); + ctxClass.addInitializer(() => log.push("c4")); +}; +{ + let _initClass, _classDecs; + const log = []; + _classDecs = [classDec1(log), classDec2(log)]; + let _C; + class C { + static { + [_C, _initClass] = babelHelpers.applyDecs2311(this, _classDecs, []).c; + } + [log.push("k1")]; + [log.push("k2")]; + [log.push("k3")]; + static { + _initClass(); + } + } + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + let _initClass2, _classDecs2, _computedKey; + const log = []; + _classDecs2 = [classDec1(log), classDec2(log)]; + let _C2; + new class extends babelHelpers.identity { + static [class C { + static { + [_C2, _initClass2] = babelHelpers.applyDecs2311(this, _classDecs2, []).c; + } + async [(_computedKey = log.push("k1"), log.push("k2"))](v) {} + [log.push("k3")]; + }]; + [_computedKey]; + constructor() { + super(_C2), _initClass2(); + } + }(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + let _initClass3, _classDecs3, _computedKey2; + const log = []; + _classDecs3 = [classDec1(log), classDec2(log)]; + let _C3; + new class extends babelHelpers.identity { + static [class C { + static { + [_C3, _initClass3] = babelHelpers.applyDecs2311(this, _classDecs3, []).c; + } + get [log.push("k1")]() {} + [(_computedKey2 = log.push("k2"), log.push("k3"))]; + }]; + [_computedKey2]; + constructor() { + super(_C3), _initClass3(); + } + }(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + let _computedKey3, _initClass4, _classDecs4, _computedKey4; + const log = []; + _classDecs4 = [classDec1(log), classDec2(log)]; + let _C4; + new class extends babelHelpers.identity { + static [class C { + static { + [_C4, _initClass4] = babelHelpers.applyDecs2311(this, _classDecs4, []).c; + } + [log.push("k1")]; + #A; + get [_computedKey3 = babelHelpers.toPropertyKey(log.push("k2"))]() { + return this.#A; + } + set [(_computedKey4 = log.push("k3"), _computedKey3)](v) { + this.#A = v; + } + }]; + [_computedKey4]; + constructor() { + super(_C4), _initClass4(); + } + }(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + let _initClass5, _classDecs5, _computedKey6, _computedKey7; + const log = []; + _classDecs5 = [classDec1(log), classDec2(log)]; + let _C5; + new class extends babelHelpers.identity { + static [class C { + static { + [_C5, _initClass5] = babelHelpers.applyDecs2311(this, _classDecs5, []).c; + } + static set [log.push("k1")](v) {} + [(_computedKey7 = log.push("k2"), _computedKey6 = log.push("k3"), _computedKey7)]; + }]; + [_computedKey6]; + constructor() { + super(_C5), _initClass5(); + } + }(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} +{ + let _initClass6, _classDecs6, _computedKey8, _computedKey9, _computedKey10; + const log = []; + _classDecs6 = [classDec1(log), classDec2(log)]; + let _C6; + new class extends babelHelpers.identity { + static [class C { + static [(_computedKey8 = log.push("k1"), _computedKey9 = log.push("k2"), _computedKey10 = log.push("k3"), "_")]; + static { + delete this._; + [_C6, _initClass6] = babelHelpers.applyDecs2311(this, _classDecs6, []).c; + } + }]; + [_computedKey8]; + [_computedKey9]; + [_computedKey10]; + constructor() { + super(_C6), _initClass6(); + } + }(); + expect(log.join()).toBe("k1,k2,k3," + + // ClassElementEvaluation + "c1,c2," + + // ApplyDecoratorsToClassDefinition + "c3,c4,c5,c6" // classExtraInitializers + ); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/decorators-evaluation-with-this-caching/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/decorators-evaluation-with-this-caching/input.js new file mode 100644 index 000000000000..819f9050333d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/decorators-evaluation-with-this-caching/input.js @@ -0,0 +1,7 @@ +let fn, obj; +class A { + @fn() + @obj.prop.foo + method() {} +} + diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/decorators-evaluation-with-this-caching/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/decorators-evaluation-with-this-caching/output.js new file mode 100644 index 000000000000..dfdbba783894 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/decorators-evaluation-with-this-caching/output.js @@ -0,0 +1,11 @@ +let _initProto, _obj; +let fn, obj; +class A { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[[void 0, fn(), _obj = obj.prop, _obj.foo], 18, "method"]]).e; + } + constructor() { + _initProto(this); + } + method() {} +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods-private/exec.js new file mode 100644 index 000000000000..7ae723e18de4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods-private/exec.js @@ -0,0 +1,34 @@ +var counter = 0; + +class A { + @((_, { addInitializer }) => { + addInitializer(function () { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.#foo).toBe("#foo"); + expect(() => this.#bar).toThrow(); + }); + }) + #foo = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(() => this.#foo).toThrow(); + expect(() => this.#bar).toThrow(); + return "#foo"; + })(); + + method() {} + + #bar = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.#foo).toBe("#foo"); + expect(() => this.#bar).toThrow(); + })(); +} + +expect(counter).toBe(0); + +new A(); + +expect(counter).toBe(3); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods-private/input.js new file mode 100644 index 000000000000..7ae723e18de4 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods-private/input.js @@ -0,0 +1,34 @@ +var counter = 0; + +class A { + @((_, { addInitializer }) => { + addInitializer(function () { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.#foo).toBe("#foo"); + expect(() => this.#bar).toThrow(); + }); + }) + #foo = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(() => this.#foo).toThrow(); + expect(() => this.#bar).toThrow(); + return "#foo"; + })(); + + method() {} + + #bar = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.#foo).toBe("#foo"); + expect(() => this.#bar).toThrow(); + })(); +} + +expect(counter).toBe(0); + +new A(); + +expect(counter).toBe(3); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods-private/output.js new file mode 100644 index 000000000000..f89c28797bb9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods-private/output.js @@ -0,0 +1,33 @@ +let _fooDecs, _init_foo, _init_extra_foo; +var counter = 0; +class A { + static { + [_init_foo, _init_extra_foo] = babelHelpers.applyDecs2311(this, [], [[_fooDecs, 0, "foo", o => o.#foo, (o, v) => o.#foo = v]], 0, _ => #bar in _).e; + } + #foo = _init_foo(this, (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(() => this.#foo).toThrow(); + expect(() => this.#bar).toThrow(); + return "#foo"; + })()); + [(_fooDecs = (_, { + addInitializer + }) => { + addInitializer(function () { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.#foo).toBe("#foo"); + expect(() => this.#bar).toThrow(); + }); + }, "method")]() {} + #bar = (_init_extra_foo(this), (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.#foo).toBe("#foo"); + expect(() => this.#bar).toThrow(); + })()); +} +expect(counter).toBe(0); +new A(); +expect(counter).toBe(3); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods/exec.js new file mode 100644 index 000000000000..8eeb15bea635 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field-initializers-after-methods/exec.js @@ -0,0 +1,35 @@ +var counter = 0; + +@(x => x) +class A { + @((_, { addInitializer }) => { + addInitializer(function () { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.foo).toBe("foo"); + expect(this.bar).toBeUndefined(); + }); + }) + foo = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.foo).toBeUndefined(); + expect(this.bar).toBeUndefined(); + return "foo"; + })(); + + method() {} + + bar = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.foo).toBe("foo"); + expect(this.bar).toBeUndefined(); + })(); +} + +expect(counter).toBe(0); + +new A(); + +expect(counter).toBe(3); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field/exec.js new file mode 100644 index 000000000000..7a51e8b93b7e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/field/exec.js @@ -0,0 +1,31 @@ +var log = []; + +function push(x) { log.push(x); return x; } + +function logDecoratorRun(a, b) { + push(a); + return function (el) { push(b); return el; }; +} + +@logDecoratorRun(0, 21) +@logDecoratorRun(1, 20) +class A { + @logDecoratorRun(2, 17) + @logDecoratorRun(3, 16) + [push(4)]; + + @logDecoratorRun(5, 13) + @logDecoratorRun(6, 12) + static [push(7)]; + + @logDecoratorRun(8, 15) + @logDecoratorRun(9, 14) + static #c; + + @logDecoratorRun(10, 19) + @logDecoratorRun(11, 18) + #d; +} + +var nums = Array.from({ length: 22 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/initializers-and-static-blocks/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/initializers-and-static-blocks/exec.js new file mode 100644 index 000000000000..b3ef6feb24bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/initializers-and-static-blocks/exec.js @@ -0,0 +1,217 @@ +const log = []; +const classDec1 = (cls, ctxClass) => { + log.push("c2"); + ctxClass.addInitializer(() => log.push("c5")); + ctxClass.addInitializer(() => log.push("c6")); +}; +const classDec2 = (cls, ctxClass) => { + log.push("c1"); + ctxClass.addInitializer(() => log.push("c3")); + ctxClass.addInitializer(() => log.push("c4")); +}; +const methodDec1 = (fn, ctxMethod) => { + log.push("m2"); + ctxMethod.addInitializer(() => log.push("m5")); + ctxMethod.addInitializer(() => log.push("m6")); +}; +const methodDec2 = (fn, ctxMethod) => { + log.push("m1"); + ctxMethod.addInitializer(() => log.push("m3")); + ctxMethod.addInitializer(() => log.push("m4")); +}; +const staticMethodDec1 = (fn, ctxStaticMethod) => { + log.push("M2"); + ctxStaticMethod.addInitializer(() => log.push("M5")); + ctxStaticMethod.addInitializer(() => log.push("M6")); +}; +const staticMethodDec2 = (fn, ctxStaticMethod) => { + log.push("M1"); + ctxStaticMethod.addInitializer(() => log.push("M3")); + ctxStaticMethod.addInitializer(() => log.push("M4")); +}; +const fieldDec1 = (value, ctxField) => { + log.push("f2"); + ctxField.addInitializer(() => log.push("f7")); + ctxField.addInitializer(() => log.push("f8")); + return () => { + log.push("f3"); + }; +}; +const fieldDec2 = (value, ctxField) => { + log.push("f1"); + ctxField.addInitializer(() => log.push("f5")); + ctxField.addInitializer(() => log.push("f6")); + return () => { + log.push("f4"); + }; +}; +const staticFieldDec1 = (value, ctxStaticField) => { + log.push("F2"); + ctxStaticField.addInitializer(() => log.push("F7")); + ctxStaticField.addInitializer(() => log.push("F8")); + return () => { + log.push("F3"); + }; +}; +const staticFieldDec2 = (value, ctxStaticField) => { + log.push("F1"); + ctxStaticField.addInitializer(() => log.push("F5")); + ctxStaticField.addInitializer(() => log.push("F6")); + return () => { + log.push("F4"); + }; +}; +const getterDec1 = (fn, ctxGetter) => { + log.push("g2"); + ctxGetter.addInitializer(() => log.push("g5")); + ctxGetter.addInitializer(() => log.push("g6")); +}; +const getterDec2 = (fn, ctxGetter) => { + log.push("g1"); + ctxGetter.addInitializer(() => log.push("g3")); + ctxGetter.addInitializer(() => log.push("g4")); +}; +const staticGetterDec1 = (fn, ctxStaticGetter) => { + log.push("G2"); + ctxStaticGetter.addInitializer(() => log.push("G5")); + ctxStaticGetter.addInitializer(() => log.push("G6")); +}; +const staticGetterDec2 = (fn, ctxStaticGetter) => { + log.push("G1"); + ctxStaticGetter.addInitializer(() => log.push("G3")); + ctxStaticGetter.addInitializer(() => log.push("G4")); +}; +const setterDec1 = (fn, ctxSetter) => { + log.push("s2"); + ctxSetter.addInitializer(() => log.push("s5")); + ctxSetter.addInitializer(() => log.push("s6")); +}; +const setterDec2 = (fn, ctxSetter) => { + log.push("s1"); + ctxSetter.addInitializer(() => log.push("s3")); + ctxSetter.addInitializer(() => log.push("s4")); +}; +const staticSetterDec1 = (fn, ctxStaticSetter) => { + log.push("S2"); + ctxStaticSetter.addInitializer(() => log.push("S5")); + ctxStaticSetter.addInitializer(() => log.push("S6")); +}; +const staticSetterDec2 = (fn, ctxStaticSetter) => { + log.push("S1"); + ctxStaticSetter.addInitializer(() => log.push("S3")); + ctxStaticSetter.addInitializer(() => log.push("S4")); +}; +const accessorDec1 = (target, ctxAccessor) => { + log.push("a2"); + ctxAccessor.addInitializer(() => log.push("a7")); + ctxAccessor.addInitializer(() => log.push("a8")); + return { init() { + log.push("a3"); + } }; +}; +const accessorDec2 = (target, ctxAccessor) => { + log.push("a1"); + ctxAccessor.addInitializer(() => log.push("a5")); + ctxAccessor.addInitializer(() => log.push("a6")); + return { init() { + log.push("a4"); + } }; +}; +const staticAccessorDec1 = (target, ctxStaticAccessor) => { + log.push("A2"); + ctxStaticAccessor.addInitializer(() => log.push("A7")); + ctxStaticAccessor.addInitializer(() => log.push("A8")); + return { init() { + log.push("A3"); + } }; +}; +const staticAccessorDec2 = (target, ctxStaticAccessor) => { + log.push("A1"); + ctxStaticAccessor.addInitializer(() => log.push("A5")); + ctxStaticAccessor.addInitializer(() => log.push("A6")); + return { init() { + log.push("A4"); + } }; +}; +log.push("start"); +@classDec1 +@classDec2 +class Foo extends (log.push("extends"), Object) { + static { + log.push("static:start"); + } + constructor() { + log.push("ctor:start"); + super(); + log.push("ctor:end"); + } + @methodDec1 + @methodDec2 + method() { + } + @staticMethodDec1 + @staticMethodDec2 + static method() { + } + @fieldDec1 + @fieldDec2 + field; + @staticFieldDec1 + @staticFieldDec2 + static field; + @getterDec1 + @getterDec2 + get getter() { + return; + } + @staticGetterDec1 + @staticGetterDec2 + static get getter() { + return; + } + @setterDec1 + @setterDec2 + set setter(x) { + } + @staticSetterDec1 + @staticSetterDec2 + static set getter(x) { + } + @accessorDec1 + @accessorDec2 + accessor accessor; + @staticAccessorDec1 + @staticAccessorDec2 + static accessor accessor; + static { + log.push("static:end"); + } +} +log.push("after"); +new Foo(); +log.push("end"); +expect(log + "").toEqual( + 'start,extends,' + + 'M1,M2,G1,G2,S1,S2,A1,A2,' + // For each element e of staticElements if e.[[Kind]] is not field + 'm1,m2,g1,g2,s1,s2,a1,a2,' + // For each element e of instanceElements if e.[[Kind]] is not field + 'F1,F2,' + // For each element e of staticElements if e.[[Kind]] is field + 'f1,f2,' + // For each element e of instanceElements if e.[[Kind]] is field + 'c1,c2,' + // ApplyDecoratorsToClassDefinition + 'M3,M4,M5,M6,G3,G4,G5,G6,S3,S4,S5,S6,' + // staticExtraInitializers + 'static:start,' + // staticElements + 'F3,F4,' + // InitializeFieldOrAccessor + 'F5,F6,F7,F8,' + // field extraInitializers + 'A3,A4,' + // InitializeFieldOrAccessor + 'A5,A6,A7,A8,' + // accessor extraInitializers + 'static:end,' + // staticElements + 'c3,c4,c5,c6,' + // classExtraInitializers + 'after,' + + 'ctor:start,' + + 'm3,m4,m5,m6,g3,g4,g5,g6,s3,s4,s5,s6,' + // instanceExtraInitializers + 'f3,f4,' + // InitializeFieldOrAccessor + 'f5,f6,f7,f8,' + // field extraInitializers + 'a3,a4,' + // InitializeFieldOrAccessor + 'a5,a6,a7,a8,' + // field extraInitializers + 'ctor:end,' + + 'end' +); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/initializers/exec.js new file mode 100644 index 000000000000..2a43cb651ee9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/initializers/exec.js @@ -0,0 +1,56 @@ +var log = []; + +function push(x) { log.push(x); return x; } + +function logDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { push(c); }); + return el; + }; +} + +@logDecoratorRun(0, 35, 45) +@logDecoratorRun(1, 34, 44) +class A { + @logDecoratorRun(2, 27, 47) + @logDecoratorRun(3, 26, 46) + a() {}; + + @logDecoratorRun(4, 19, 37) + @logDecoratorRun(5, 18, 36) + static b() {}; + + @logDecoratorRun(6, 21, 39) + @logDecoratorRun(7, 20, 38) + static #c() {}; + + @logDecoratorRun(8, 29, 49) + @logDecoratorRun(9, 28, 48) + #d() {}; + + @logDecoratorRun(10, 31, 51) + @logDecoratorRun(11, 30, 50) + accessor e; + + @logDecoratorRun(12, 23, 41) + @logDecoratorRun(13, 22, 40) + static accessor f; + + @logDecoratorRun(14, 25, 43) + @logDecoratorRun(15, 24, 42) + static accessor #g; + + @logDecoratorRun(16, 33, 53) + @logDecoratorRun(17, 32, 52) + accessor #h; +} + +var nums = Array.from({ length: 46 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 54 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/method-initializers-field-value/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/method-initializers-field-value/exec.js new file mode 100644 index 000000000000..c1aacb35624e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/method-initializers-field-value/exec.js @@ -0,0 +1,153 @@ +{ + const log = []; + const methodDec1 = (fn, ctxMethod) => { + log.push("m2"); + ctxMethod.addInitializer(() => log.push("m5")); + ctxMethod.addInitializer(() => log.push("m6")); + }; + const methodDec2 = (fn, ctxMethod) => { + log.push("m1"); + ctxMethod.addInitializer(() => log.push("m3")); + ctxMethod.addInitializer(() => log.push("m4")); + }; + const getterDec1 = (fn, ctxGetter) => { + log.push("g2"); + ctxGetter.addInitializer(() => log.push("g5")); + ctxGetter.addInitializer(() => log.push("g6")); + }; + const getterDec2 = (fn, ctxGetter) => { + log.push("g1"); + ctxGetter.addInitializer(() => log.push("g3")); + ctxGetter.addInitializer(() => log.push("g4")); + }; + const setterDec1 = (fn, ctxSetter) => { + log.push("s2"); + ctxSetter.addInitializer(() => log.push("s5")); + ctxSetter.addInitializer(() => log.push("s6")); + }; + const setterDec2 = (fn, ctxSetter) => { + log.push("s1"); + ctxSetter.addInitializer(() => log.push("s3")); + ctxSetter.addInitializer(() => log.push("s4")); + }; + log.push("start"); + class Foo extends (log.push("extends"), Object) { + static { + log.push("static:start"); + } + constructor() { + log.push("ctor:start"); + super(); + log.push("ctor:end"); + } + @methodDec1 + @methodDec2 + method() {} + + field = log.push("f"); + + @getterDec1 + @getterDec2 + get getter() { + return; + } + @setterDec1 + @setterDec2 + set setter(x) {} + static { + log.push("static:end"); + } + } + log.push("after"); + new Foo(); + log.push("end"); + expect(log + "").toEqual( + "start,extends," + + "m1,m2,g1,g2,s1,s2," + // For each element e of instanceElements if e.[[Kind]] is not field + "static:start," + // staticElements + "static:end," + // staticElements + "after," + + "ctor:start," + + "m3,m4,m5,m6,g3,g4,g5,g6,s3,s4,s5,s6," + // instanceExtraInitializers + "f," + // InitializeFieldOrAccessor + "ctor:end," + + "end", + ); +} + +{ + const log = []; + const methodDec1 = (fn, ctxMethod) => { + log.push("m2"); + ctxMethod.addInitializer(() => log.push("m5")); + ctxMethod.addInitializer(() => log.push("m6")); + }; + const methodDec2 = (fn, ctxMethod) => { + log.push("m1"); + ctxMethod.addInitializer(() => log.push("m3")); + ctxMethod.addInitializer(() => log.push("m4")); + }; + const getterDec1 = (fn, ctxGetter) => { + log.push("g2"); + ctxGetter.addInitializer(() => log.push("g5")); + ctxGetter.addInitializer(() => log.push("g6")); + }; + const getterDec2 = (fn, ctxGetter) => { + log.push("g1"); + ctxGetter.addInitializer(() => log.push("g3")); + ctxGetter.addInitializer(() => log.push("g4")); + }; + const setterDec1 = (fn, ctxSetter) => { + log.push("s2"); + ctxSetter.addInitializer(() => log.push("s5")); + ctxSetter.addInitializer(() => log.push("s6")); + }; + const setterDec2 = (fn, ctxSetter) => { + log.push("s1"); + ctxSetter.addInitializer(() => log.push("s3")); + ctxSetter.addInitializer(() => log.push("s4")); + }; + log.push("start"); + class Foo extends (log.push("extends"), Object) { + static { + log.push("static:start"); + } + constructor() { + log.push("ctor:start"); + super(); + log.push("ctor:end"); + } + @methodDec1 + @methodDec2 + method() {} + + accessor field = log.push("a"); + + @getterDec1 + @getterDec2 + get getter() { + return; + } + @setterDec1 + @setterDec2 + set setter(x) {} + static { + log.push("static:end"); + } + } + log.push("after"); + new Foo(); + log.push("end"); + expect(log + "").toEqual( + "start,extends," + + "m1,m2,g1,g2,s1,s2," + // For each element e of instanceElements if e.[[Kind]] is not field + "static:start," + // staticElements + "static:end," + // staticElements + "after," + + "ctor:start," + + "m3,m4,m5,m6,g3,g4,g5,g6,s3,s4,s5,s6," + // instanceExtraInitializers + "a," + // InitializeFieldOrAccessor + "ctor:end," + + "end", + ); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/options.json new file mode 100644 index 000000000000..154ee22b969c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/options.json @@ -0,0 +1,4 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]], + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/static-accessor-method-initializers/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/static-accessor-method-initializers/exec.js new file mode 100644 index 000000000000..b776def232c5 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/static-accessor-method-initializers/exec.js @@ -0,0 +1,74 @@ +var log = []; + +function push(x) { + log.push(x); + return x; +} + +function logClassDecoratorRun(a, b, c) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return el; + }; +} + +function logAccessorDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return { + init: () => push(d), + }; + }; +} + +function logMethodDecoratorRun(a, b, c, d) { + push(a); + return function (el, { addInitializer }) { + push(b); + addInitializer(function () { + push(c); + }); + return () => (el(), push(d)) + }; +} + +@logClassDecoratorRun(0, 19, 29) +@logClassDecoratorRun(1, 18, 28) +class A { + @logMethodDecoratorRun(2, 15, 31, 35) + @logMethodDecoratorRun(3, 14, 30, 34) + a() {} + + @logAccessorDecoratorRun(4, 11, 23, 20) + @logAccessorDecoratorRun(5, 10, 22, 21) + static accessor b; + + @logAccessorDecoratorRun(6, 13, 27, 24) + @logAccessorDecoratorRun(7, 12, 26, 25) + static accessor #c; + + @logMethodDecoratorRun(8, 17, 33, 37) + @logMethodDecoratorRun(9, 16, 32, 36) + #d() {} + + constructor() { + this.a(); + this.#d(); + } +} + +var nums = Array.from({ length: 30 }, (_, i) => i); +expect(log).toEqual(nums); + +new A(); + +var nums = Array.from({ length: 38 }, (_, i) => i); +expect(log).toEqual(nums); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/static-field-initializers-after-methods/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/static-field-initializers-after-methods/exec.js new file mode 100644 index 000000000000..0703f091cc8d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-ordering/static-field-initializers-after-methods/exec.js @@ -0,0 +1,23 @@ +var counter = 0; + +@(x => x) +class A { + static foo = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.foo).toBeUndefined(); + expect(this.bar).toBeUndefined(); + return "foo"; + })(); + + static method() {} + + static bar = (() => { + counter++; + expect(typeof this.method).toBe("function"); + expect(this.foo).toBe("foo"); + expect(this.bar).toBeUndefined(); + })(); +} + +expect(counter).toBe(2); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-accessor-decorator-return/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-accessor-decorator-return/exec.js new file mode 100644 index 000000000000..2621e3fdba3c --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-accessor-decorator-return/exec.js @@ -0,0 +1,20 @@ +const returnsUndefined = () => void 0; +const returnsNull = () => null; +const returnsFalse = () => false; +const returnsFunction = () => () => {} +const returnsGetSet = () => ({ set(v) {}, get() {} }); +const returnsInit = () => ({ init() {} }); +const returnsGetFalse = () => ({ get: false }); +const returnsSetFalse = () => ({ set: false }); +const returnsInitFalse = () => ({ init: false }); + +expect(() => class { @returnsNull accessor a }).toThrow("accessor decorators must return an object with get, set, or init properties or undefined") +expect(() => class { @returnsFalse accessor a }).toThrow("accessor decorators must return an object with get, set, or init properties or undefined") +expect(() => class { @returnsFunction accessor a }).toThrow("accessor decorators must return an object with get, set, or init properties or undefined") +expect(() => class { @returnsGetFalse accessor a }).toThrow("accessor.get must be a function"); +expect(() => class { @returnsSetFalse accessor a }).toThrow("accessor.set must be a function"); +expect(() => class { @returnsInitFalse accessor a }).toThrow("accessor.init must be a function"); + +expect(() => class { @returnsGetSet accessor a }).not.toThrow(); +expect(() => class { @returnsInit accessor a }).not.toThrow(); +expect(() => class { @returnsUndefined accessor a }).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-add-initializer/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-add-initializer/exec.js new file mode 100644 index 000000000000..a91c771ca9b8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-add-initializer/exec.js @@ -0,0 +1,6 @@ +const decWithInitializer = (init) => (_, context) => { context.addInitializer(init) } + +expect(() => class { @decWithInitializer(null) static m() {} }).toThrow("An initializer must be a function") +expect(() => class { @decWithInitializer(false) static m() {} }).toThrow("An initializer must be a function") +expect(() => class { @decWithInitializer(void 0) static m() {} }).toThrow("An initializer must be a function"); +expect(() => class { @decWithInitializer(() => {}) static m() {} }).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-class-decorator-return/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-class-decorator-return/exec.js new file mode 100644 index 000000000000..030fdfcc5875 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-class-decorator-return/exec.js @@ -0,0 +1,9 @@ +const returnsUndefined = () => void 0; +const returnsNull = () => null; +const returnsFalse = () => false; +const returnsFunction = () => () => {}; + +expect(() => @returnsNull class {}).toThrow("class decorators must return a function or undefined") +expect(() => @returnsFalse class {}).toThrow("class decorators must return a function or undefined") +expect(() => @returnsFunction class {}).not.toThrow(); +expect(() => @returnsUndefined class {}).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-field-decorator-return/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-field-decorator-return/exec.js new file mode 100644 index 000000000000..153745c346fe --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-field-decorator-return/exec.js @@ -0,0 +1,9 @@ +const returnsUndefined = () => void 0; +const returnsNull = () => null; +const returnsFalse = () => false; +const returnsFunction = () => () => {}; + +expect(() => class { @returnsNull m() {} }).toThrow("method decorators must return a function or undefined") +expect(() => class { @returnsFalse m() {} }).toThrow("method decorators must return a function or undefined") +expect(() => class { @returnsFunction m() {} }).not.toThrow(); +expect(() => class { @returnsUndefined m() {} }).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-getter-decorator-return/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-getter-decorator-return/exec.js new file mode 100644 index 000000000000..87c3c1b627a7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-getter-decorator-return/exec.js @@ -0,0 +1,9 @@ +const returnsUndefined = () => void 0; +const returnsNull = () => null; +const returnsFalse = () => false; +const returnsFunction = () => () => {}; + +expect(() => class { @returnsNull get p() {} }).toThrow("method decorators must return a function or undefined") +expect(() => class { @returnsFalse get p() {} }).toThrow("method decorators must return a function or undefined") +expect(() => class { @returnsFunction get p() {} }).not.toThrow(); +expect(() => class { @returnsUndefined get p() {} }).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-method-decorator-return/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-method-decorator-return/exec.js new file mode 100644 index 000000000000..505898f4fbb8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-method-decorator-return/exec.js @@ -0,0 +1,9 @@ +const returnsUndefined = () => void 0; +const returnsNull = () => null; +const returnsFalse = () => false; +const returnsFunction = () => () => {}; + +expect(() => class { @returnsNull p }).toThrow("field decorators must return a function or undefined") +expect(() => class { @returnsFalse p }).toThrow("field decorators must return a function or undefined") +expect(() => class { @returnsFunction p }).not.toThrow(); +expect(() => class { @returnsUndefined p }).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-setter-decorator-return/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-setter-decorator-return/exec.js new file mode 100644 index 000000000000..6ad588facaae --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/invalid-setter-decorator-return/exec.js @@ -0,0 +1,9 @@ +const returnsUndefined = () => void 0; +const returnsNull = () => null; +const returnsFalse = () => false; +const returnsFunction = () => () => {}; + +expect(() => class { @returnsNull set p(v) {} }).toThrow("method decorators must return a function or undefined") +expect(() => class { @returnsFalse set p(v) {} }).toThrow("method decorators must return a function or undefined") +expect(() => class { @returnsFunction set p(v) {} }).not.toThrow(); +expect(() => class { @returnsUndefined set p(v) {} }).not.toThrow(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-runtime-errors--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/exec.js new file mode 100644 index 000000000000..905ff9aa4e25 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static set a(v) {}; + @dec static set #a(v) {}; + + @dec static set "b"(v) {} + @dec static set ["c"](v) {}; + + @dec static set 0(v) {}; + @dec static set [1](v) {}; + + @dec static set 2n(v) {}; + @dec static set [3n](v) {}; + + @dec static set [f()](v) {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/input.js new file mode 100644 index 000000000000..905ff9aa4e25 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static set a(v) {}; + @dec static set #a(v) {}; + + @dec static set "b"(v) {} + @dec static set ["c"](v) {}; + + @dec static set 0(v) {}; + @dec static set [1](v) {}; + + @dec static set 2n(v) {}; + @dec static set [3n](v) {}; + + @dec static set [f()](v) {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/options.json new file mode 100644 index 000000000000..e6953fa50f0b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "14.6.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/output.js new file mode 100644 index 000000000000..2ad29e6ae9a1 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/context-name/output.js @@ -0,0 +1,29 @@ +var _Foo; +let _initStatic, _call_a, _computedKey; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +_computedKey = babelHelpers.toPropertyKey(f()); +class Foo { + static set a(v) {} + static set "b"(v) {} + static set ["c"](v) {} + static set 0(v) {} + static set [1](v) {} + static set 2n(v) {} + static set [3n](v) {} + static set [_computedKey](v) {} +} +_Foo = Foo; +(() => { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 12, "a"], [dec, 12, "a", function (v) {}], [dec, 12, "b"], [dec, 12, "c"], [dec, 12, 0], [dec, 12, 1], [dec, 12, 2n], [dec, 12, 3n], [dec, 12, _computedKey]]).e; + _initStatic(_Foo); +})(); +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/options.json new file mode 100644 index 000000000000..e98ba8f3cd5b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2023-11" }], + "transform-class-properties", + "transform-private-methods", + "transform-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/private/exec.js new file mode 100644 index 000000000000..f28fec2051f8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/private/exec.js @@ -0,0 +1,47 @@ +function dec(set, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(set.name).toEqual("set " + context.name); + return function (v) { + return set.call(this, v + 1); + } +} + +class Foo { + value = 1; + + @dec + set #a(v) { + return this.value = v; + } + + setA(v) { + this.#a = v; + } +} + +let foo = new Foo(); + +const aContext = foo['#aContext']; + +expect(aContext.access).not.toHaveProperty("get"); + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(false); + +expect(foo.value).toBe(1); +aContext.access.set(foo, 123); +expect(foo.value).toBe(124); +expect(() => aContext.access.set({}, 456)).toThrow(TypeError); +expect(foo.value).toBe(124); +foo.setA(456); +expect(foo.value).toBe(457); + +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('setter'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/private/input.js new file mode 100644 index 000000000000..66dd78268d19 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + set #a(v) { + return this.value = v; + } + + setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/private/output.js new file mode 100644 index 000000000000..c9f290bd5d97 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/private/output.js @@ -0,0 +1,17 @@ +var _Foo; +let _initProto, _call_a; +const dec = () => {}; +var _Foo_brand = /*#__PURE__*/new WeakSet(); +class Foo { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Foo_brand); + babelHelpers.defineProperty(this, "value", (_initProto(this), 1)); + } + setA(v) { + babelHelpers.classPrivateSetter(_Foo_brand, _call_a, this, v); + } +} +_Foo = Foo; +[_call_a, _initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 4, "a", function (v) { + return this.value = v; +}]], 0, _ => _Foo_brand.has(babelHelpers.checkInRHS(_))).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/public/exec.js new file mode 100644 index 000000000000..84576bc0e91f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/public/exec.js @@ -0,0 +1,56 @@ +function dec(set, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(set.name).toEqual("set " + context.name); + return function (v) { + return set.call(this, v + 1); + } +} + +class Foo { + value = 1; + + @dec + set a(v) { + return this.value = v; + } + + @dec + set ['b'](v) { + return this.value = v; + } +} + +let foo = new Foo(); + +const aContext = foo['aContext']; +const bContext = foo['bContext']; + +expect(aContext.access).not.toHaveProperty("get"); +expect(bContext.access).not.toHaveProperty("get"); + +expect(aContext.access.has(foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(foo.value).toBe(1); +foo.a = 123; +expect(foo.value).toBe(124); +aContext.access.set(foo, 456); +expect(foo.value).toBe(457); + +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('setter'); +expect(aContext.static).toBe(false); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('setter'); +expect(bContext.static).toBe(false); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/public/input.js new file mode 100644 index 000000000000..9a7faf175edd --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + set a(v) { + return this.value = v; + } + + @dec + set ['b'](v) { + return this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/public/output.js new file mode 100644 index 000000000000..6a02f053b29d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/public/output.js @@ -0,0 +1,16 @@ +var _Foo; +let _initProto; +const dec = () => {}; +class Foo { + constructor() { + babelHelpers.defineProperty(this, "value", (_initProto(this), 1)); + } + set a(v) { + return this.value = v; + } + set ['b'](v) { + return this.value = v; + } +} +_Foo = Foo; +[_initProto] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 4, "a"], [dec, 4, 'b']]).e; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-private/exec.js new file mode 100644 index 000000000000..5d6141f742cb --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-private/exec.js @@ -0,0 +1,45 @@ +function dec(set, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(set.name).toEqual("set " + context.name); + return function (v) { + return set.call(this, v + 1); + } +} + +class Foo { + static value = 1; + + @dec + static set #a(v) { + return this.value = v; + } + + static setA(v) { + this.#a = v; + } +} + +const aContext = Foo['#aContext']; + +expect(aContext.access).not.toHaveProperty("get"); + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(false); + +expect(Foo.value).toBe(1); +aContext.access.set(Foo, 123); +expect(Foo.value).toBe(124); +expect(() => aContext.access.set({}, 456)).toThrow(TypeError); +expect(Foo.value).toBe(124); +Foo.setA(456); +expect(Foo.value).toBe(457); + +expect(aContext.name).toBe('#a'); +expect(aContext.kind).toBe('setter'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(true); +expect(typeof aContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-private/input.js new file mode 100644 index 000000000000..6bf29a2a2c94 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static set #a(v) { + return this.value = v; + } + + static setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-private/output.js new file mode 100644 index 000000000000..26b57329e144 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-private/output.js @@ -0,0 +1,16 @@ +var _Foo; +let _initStatic, _call_a; +const dec = () => {}; +class Foo { + static setA(v) { + babelHelpers.classPrivateSetter(Foo, _call_a, this, v); + } +} +_Foo = Foo; +(() => { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 12, "a", function (v) { + return this.value = v; + }]]).e; + _initStatic(_Foo); +})(); +babelHelpers.defineProperty(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-public/exec.js new file mode 100644 index 000000000000..79a9fccf013a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-public/exec.js @@ -0,0 +1,54 @@ +function dec(set, context) { + context.addInitializer(function() { + this[context.name + 'Context'] = context; + }); + + expect(set.name).toEqual("set " + context.name); + return function (v) { + return set.call(this, v + 1); + } +} + +class Foo { + static value = 1; + + @dec + static set a(v) { + return this.value = v; + } + + @dec + static set ['b'](v) { + return this.value = v; + } +} + +const aContext = Foo['aContext']; +const bContext = Foo['bContext']; + +expect(aContext.access).not.toHaveProperty("get"); +expect(bContext.access).not.toHaveProperty("get"); + +expect(aContext.access.has(Foo)).toBe(true); +expect(aContext.access.has({})).toBe(false); +expect(aContext.access.has(Object.create(Foo))).toBe(true); +expect(aContext.access.has({ a: 1 })).toBe(true); +expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true); + +expect(Foo.value).toBe(1); +Foo.a = 123; +expect(Foo.value).toBe(124); +aContext.access.set(Foo, 456); +expect(Foo.value).toBe(457); + +expect(aContext.name).toBe('a'); +expect(aContext.kind).toBe('setter'); +expect(aContext.static).toBe(true); +expect(aContext.private).toBe(false); +expect(typeof aContext.addInitializer).toBe('function'); + +expect(bContext.name).toBe('b'); +expect(bContext.kind).toBe('setter'); +expect(bContext.static).toBe(true); +expect(bContext.private).toBe(false); +expect(typeof bContext.addInitializer).toBe('function'); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-public/input.js new file mode 100644 index 000000000000..ed0a661dcb2d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static set a(v) { + return this.value = v; + } + + @dec + static set ['b'](v) { + return this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-public/output.js new file mode 100644 index 000000000000..2ac86dae0f74 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters--to-es2015/static-public/output.js @@ -0,0 +1,17 @@ +var _Foo; +let _initStatic; +const dec = () => {}; +class Foo { + static set a(v) { + return this.value = v; + } + static set ['b'](v) { + return this.value = v; + } +} +_Foo = Foo; +(() => { + [_initStatic] = babelHelpers.applyDecs2311(_Foo, [], [[dec, 12, "a"], [dec, 12, 'b']]).e; + _initStatic(_Foo); +})(); +babelHelpers.defineProperty(Foo, "value", 1); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/exec.js new file mode 100644 index 000000000000..905ff9aa4e25 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/exec.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static set a(v) {}; + @dec static set #a(v) {}; + + @dec static set "b"(v) {} + @dec static set ["c"](v) {}; + + @dec static set 0(v) {}; + @dec static set [1](v) {}; + + @dec static set 2n(v) {}; + @dec static set [3n](v) {}; + + @dec static set [f()](v) {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/input.js new file mode 100644 index 000000000000..905ff9aa4e25 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/input.js @@ -0,0 +1,20 @@ +const logs = []; +const dec = (value, context) => { logs.push(context.name) }; +const f = () => { logs.push("computing f"); return { [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") }; }; +class Foo { + @dec static set a(v) {}; + @dec static set #a(v) {}; + + @dec static set "b"(v) {} + @dec static set ["c"](v) {}; + + @dec static set 0(v) {}; + @dec static set [1](v) {}; + + @dec static set 2n(v) {}; + @dec static set [3n](v) {}; + + @dec static set [f()](v) {}; +} + +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/options.json new file mode 100644 index 000000000000..471e37d0359f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/output.js new file mode 100644 index 000000000000..a96ba35c59b2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/context-name/output.js @@ -0,0 +1,29 @@ +let _initStatic, _call_a, _computedKey; +const logs = []; +const dec = (value, context) => { + logs.push(context.name); +}; +const f = () => { + logs.push("computing f"); + return { + [Symbol.toPrimitive]: () => (logs.push("calling toPrimitive"), "f()") + }; +}; +class Foo { + static { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 12, "a"], [dec, 12, "a", function (v) {}], [dec, 12, "b"], [dec, 12, "c"], [dec, 12, 0], [dec, 12, 1], [dec, 12, 2n], [dec, 12, 3n], [dec, 12, _computedKey]]).e; + _initStatic(this); + } + static set a(v) {} + static set #a(v) { + _call_a(this, v); + } + static set "b"(v) {} + static set ["c"](v) {} + static set 0(v) {} + static set [1](v) {} + static set 2n(v) {} + static set [3n](v) {} + static set [_computedKey = babelHelpers.toPropertyKey(f())](v) {} +} +expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/options.json new file mode 100644 index 000000000000..4c274676d3c2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/private/input.js new file mode 100644 index 000000000000..66dd78268d19 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + set #a(v) { + return this.value = v; + } + + setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/private/output.js new file mode 100644 index 000000000000..aa8da4ccd3df --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/private/output.js @@ -0,0 +1,16 @@ +let _initProto, _call_a; +const dec = () => {}; +class Foo { + static { + [_call_a, _initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 4, "a", function (v) { + return this.value = v; + }]], 0, _ => #a in _).e; + } + value = (_initProto(this), 1); + set #a(v) { + _call_a(this, v); + } + setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/public/input.js new file mode 100644 index 000000000000..9a7faf175edd --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + value = 1; + + @dec + set a(v) { + return this.value = v; + } + + @dec + set ['b'](v) { + return this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/public/output.js new file mode 100644 index 000000000000..e6e1434eb2da --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/public/output.js @@ -0,0 +1,14 @@ +let _initProto; +const dec = () => {}; +class Foo { + static { + [_initProto] = babelHelpers.applyDecs2311(this, [], [[dec, 4, "a"], [dec, 4, 'b']]).e; + } + value = (_initProto(this), 1); + set a(v) { + return this.value = v; + } + set ['b'](v) { + return this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-private/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-private/input.js new file mode 100644 index 000000000000..6bf29a2a2c94 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-private/input.js @@ -0,0 +1,13 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static set #a(v) { + return this.value = v; + } + + static setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-private/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-private/output.js new file mode 100644 index 000000000000..e4bdfbb39ed1 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-private/output.js @@ -0,0 +1,17 @@ +let _initStatic, _call_a; +const dec = () => {}; +class Foo { + static { + [_call_a, _initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 12, "a", function (v) { + return this.value = v; + }]]).e; + _initStatic(this); + } + static value = 1; + static set #a(v) { + _call_a(this, v); + } + static setA(v) { + this.#a = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-public/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-public/input.js new file mode 100644 index 000000000000..ed0a661dcb2d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-public/input.js @@ -0,0 +1,14 @@ +const dec = () => {}; +class Foo { + static value = 1; + + @dec + static set a(v) { + return this.value = v; + } + + @dec + static set ['b'](v) { + return this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-public/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-public/output.js new file mode 100644 index 000000000000..1bf6ea5b2807 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-setters/static-public/output.js @@ -0,0 +1,15 @@ +let _initStatic; +const dec = () => {}; +class Foo { + static { + [_initStatic] = babelHelpers.applyDecs2311(this, [], [[dec, 12, "a"], [dec, 12, 'b']]).e; + _initStatic(this); + } + static value = 1; + static set a(v) { + return this.value = v; + } + static set ['b'](v) { + return this.value = v; + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/computed-key-ts-as-expression/exec.ts b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/computed-key-ts-as-expression/exec.ts new file mode 100644 index 000000000000..e5285d93a38a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/computed-key-ts-as-expression/exec.ts @@ -0,0 +1,17 @@ +function noopFactory() { return function noop(x) { return x } } + +{ + class C { + [("a1", "a2") as any]() {}; + @noopFactory(0) #p; + } + expect(new C()).toHaveProperty("a2"); +} + +{ + class C { + [("a1", ("b1", "b2")) as any]() {}; + @noopFactory(1) #p; + } + expect(new C()).toHaveProperty("b2"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/computed-key-ts-as-expression/input.ts b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/computed-key-ts-as-expression/input.ts new file mode 100644 index 000000000000..e5285d93a38a --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/computed-key-ts-as-expression/input.ts @@ -0,0 +1,17 @@ +function noopFactory() { return function noop(x) { return x } } + +{ + class C { + [("a1", "a2") as any]() {}; + @noopFactory(0) #p; + } + expect(new C()).toHaveProperty("a2"); +} + +{ + class C { + [("a1", ("b1", "b2")) as any]() {}; + @noopFactory(1) #p; + } + expect(new C()).toHaveProperty("b2"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/computed-key-ts-as-expression/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/computed-key-ts-as-expression/output.js new file mode 100644 index 000000000000..4e862b07acc2 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/computed-key-ts-as-expression/output.js @@ -0,0 +1,33 @@ +function noopFactory() { + return function noop(x) { + return x; + }; +} +{ + let _computedKey, _pDecs, _init_p, _init_extra_p; + class C { + static { + [_init_p, _init_extra_p] = babelHelpers.applyDecs2311(this, [], [[_pDecs, 0, "p", o => o.#p, (o, v) => o.#p = v]], 0, _ => #p in _).e; + } + constructor() { + _init_extra_p(this); + } + [(_computedKey = ("a1", "a2"), _pDecs = noopFactory(0), _computedKey)]() {} + #p = _init_p(this); + } + expect(new C()).toHaveProperty("a2"); +} +{ + let _computedKey3, _pDecs2, _init_p2, _init_extra_p2; + class C { + static { + [_init_p2, _init_extra_p2] = babelHelpers.applyDecs2311(this, [], [[_pDecs2, 0, "p", o => o.#p, (o, v) => o.#p = v]], 0, _ => #p in _).e; + } + constructor() { + _init_extra_p2(this); + } + [(_computedKey3 = ("a1", "b1", "b2"), _pDecs2 = noopFactory(1), _computedKey3)]() {} + #p = _init_p2(this); + } + expect(new C()).toHaveProperty("b2"); +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/options.json new file mode 100644 index 000000000000..955e929eca48 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-typescript/options.json @@ -0,0 +1,5 @@ +{ + "minNodeVersion": "16.11.0", + "plugins": [["proposal-decorators", { "version": "2023-11" }]], + "presets": [["typescript"]] +} diff --git a/packages/helpers/esm/_apply_decs_2311.js b/packages/helpers/esm/_apply_decs_2311.js new file mode 100644 index 000000000000..6228898187b0 --- /dev/null +++ b/packages/helpers/esm/_apply_decs_2311.js @@ -0,0 +1,246 @@ +import { _ as checkInRHS } from "./_check_in_rhs.js"; +import { _ as setFunctionName } from "./_set_function_name.js"; +import { _ as toPropertyKey } from "./_to_property_key.js"; + + +var PROP_KIND; +export function _apply_decs_2203_r(targetClass, classDecs, memberDecs, classDecsHaveThis, instanceBrand, parentClass) { + var symbolMetadata = Symbol.metadata || Symbol.for("Symbol.metadata"); + var defineProperty = Object.defineProperty; + var create = Object.create; + var metadata; + var existingNonFields = [ + create(null), + create(null) + ]; + var hasClassDecs = classDecs.length; + var _; + function createRunInitializers(initializers, useStaticThis, hasValue) { + return function (thisArg, value) { + if (useStaticThis) { + value = thisArg; + thisArg = targetClass; + } + for (var i = 0; i < initializers.length; i++) { + value = initializers[i].apply(thisArg, hasValue ? [ + value + ] : []); + } + return hasValue ? value : thisArg; + }; + } + function assertCallable(fn, hint1, hint2, throwUndefined) { + if (typeof fn !== "function") { + if (throwUndefined || fn !== void 0) { + throw new TypeError(hint1 + " must " + (hint2 || "be") + " a function" + (throwUndefined ? "" : " or undefined")); + } + } + return fn; + } + function applyDec(Class, decInfo, decoratorsHaveThis, name, kind, initializers, ret, isStatic, isPrivate, isField, hasPrivateBrand) { + function assertInstanceIfPrivate(target) { + if (!hasPrivateBrand(target)) { + throw new TypeError("Attempted to access private element on non-instance"); + } + } + var decs = [].concat(decInfo[0]), decVal = decInfo[3], isClass = !ret; + var isAccessor = kind === 1; + var isGetter = kind === 3; + var isSetter = kind === 4; + var isMethod = kind === 2; + function _bindPropCall(name, useStaticThis, before) { + return function (_this, value) { + if (useStaticThis) { + value = _this; + _this = Class; + } + if (before) { + before(_this); + } + return desc[name].call(_this, value); + }; + } + if (!isClass) { + var desc = {}, init = [], key = isGetter ? "get" : isSetter || isAccessor ? "set" : "value"; + if (isPrivate) { + if (isField || isAccessor) { + desc = { + get: setFunctionName(function () { + return decVal(this); + }, name, "get"), + set: function (value) { + decInfo[4](this, value); + } + }; + } else { + desc[key] = decVal; + } + if (!isField) { + setFunctionName(desc[key], name, isMethod ? "" : key); + } + } else if (!isField) { + desc = Object.getOwnPropertyDescriptor(Class, name); + } + if (!isField && !isPrivate) { + _ = existingNonFields[+isStatic][name]; + if (_ && (_ ^ kind) !== 7) { + throw new Error("Decorating two elements with the same name (" + desc[key].name + ") is not supported yet"); + } + existingNonFields[+isStatic][name] = kind < 3 ? 1 : kind; + } + } + var newValue = Class; + for (var i = decs.length - 1; i >= 0; i -= decoratorsHaveThis ? 2 : 1) { + var dec = assertCallable(decs[i], "A decorator", "be", true), decThis = decoratorsHaveThis ? decs[i - 1] : void 0; + var decoratorFinishedRef = {}; + var ctx = { + kind: [ + "field", + "accessor", + "method", + "getter", + "setter", + "class" + ][kind], + name: name, + metadata: metadata, + addInitializer: (function (decoratorFinishedRef, initializer) { + if (decoratorFinishedRef.v) { + throw new TypeError("attempted to call addInitializer after decoration was finished"); + } + assertCallable(initializer, "An initializer", "be", true); + initializers.push(initializer); + }).bind(null, decoratorFinishedRef) + }; + if (isClass) { + _ = dec.call(decThis, newValue, ctx); + decoratorFinishedRef.v = 1; + if (assertCallable(_, "class decorators", "return")) { + newValue = _; + } + } else { + ctx.static = isStatic; + ctx.private = isPrivate; + _ = ctx.access = { + has: isPrivate ? hasPrivateBrand.bind() : function (target) { + return name in target; + } + }; + if (!isSetter) { + _.get = isPrivate ? isMethod ? function (_this) { + assertInstanceIfPrivate(_this); + return desc.value; + } : _bindPropCall("get", 0, assertInstanceIfPrivate) : function (target) { + return target[name]; + }; + } + if (!isMethod && !isGetter) { + _.set = isPrivate ? _bindPropCall("set", 0, assertInstanceIfPrivate) : function (target, v) { + target[name] = v; + }; + } + newValue = dec.call(decThis, isAccessor ? { + get: desc.get, + set: desc.set + } : desc[key], ctx); + decoratorFinishedRef.v = 1; + if (isAccessor) { + if (typeof newValue === "object" && newValue) { + if (_ = assertCallable(newValue.get, "accessor.get")) { + desc.get = _; + } + if (_ = assertCallable(newValue.set, "accessor.set")) { + desc.set = _; + } + if (_ = assertCallable(newValue.init, "accessor.init")) { + init.unshift(_); + } + } else if (newValue !== void 0) { + throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); + } + } else if (assertCallable(newValue, (isField ? "field" : "method") + " decorators", "return")) { + if (isField) { + init.unshift(newValue); + } else { + desc[key] = newValue; + } + } + } + } + if (kind < 2) { + ret.push(createRunInitializers(init, isStatic, 1), createRunInitializers(initializers, isStatic, 0)); + } + if (!isField && !isClass) { + if (isPrivate) { + if (isAccessor) { + ret.splice(-1, 0, _bindPropCall("get", isStatic), _bindPropCall("set", isStatic)); + } else { + ret.push(isMethod ? desc[key] : assertCallable.call.bind(desc[key])); + } + } else { + defineProperty(Class, name, desc); + } + } + return newValue; + } + function applyMemberDecs() { + var ret = []; + var protoInitializers; + var staticInitializers; + var pushInitializers = function (initializers) { + if (initializers) { + ret.push(createRunInitializers(initializers)); + } + }; + var applyMemberDecsOfKind = function (isStatic, isField) { + for (var i = 0; i < memberDecs.length; i++) { + var decInfo = memberDecs[i]; + var kind = decInfo[1]; + var kindOnly = kind & 7; + if ((kind & 8) == isStatic && !kindOnly == isField) { + var name = decInfo[2]; + var isPrivate = !!decInfo[3]; + var decoratorsHaveThis = kind & 16; + applyDec(isStatic ? targetClass : targetClass.prototype, decInfo, decoratorsHaveThis, isPrivate ? "#" + name : toPropertyKey(name), kindOnly, kindOnly < 2 ? [] : isStatic ? staticInitializers = staticInitializers || [] : protoInitializers = protoInitializers || [], ret, !!isStatic, isPrivate, isField, isStatic && isPrivate ? function (_) { + return checkInRHS(_) === targetClass; + } : instanceBrand); + } + } + }; + applyMemberDecsOfKind(8, 0); + applyMemberDecsOfKind(0, 0); + applyMemberDecsOfKind(8, 1); + applyMemberDecsOfKind(0, 1); + pushInitializers(protoInitializers); + pushInitializers(staticInitializers); + return ret; + } + function defineMetadata(Class) { + return defineProperty(Class, symbolMetadata, { + configurable: true, + enumerable: true, + value: metadata + }); + } + if (parentClass !== undefined) { + metadata = parentClass[symbolMetadata]; + } + metadata = create(metadata == null ? null : metadata); + _ = applyMemberDecs(); + if (!hasClassDecs) defineMetadata(targetClass); + return { + e: _, + get c() { + var initializers = []; + return hasClassDecs && [ + defineMetadata(targetClass = applyDec(targetClass, [ + classDecs + ], classDecsHaveThis, targetClass.name, 5, initializers)), + createRunInitializers(initializers, 1) + ]; + } + }; +} + + +export { _apply_decs_2203_r as _ } \ No newline at end of file diff --git a/packages/helpers/esm/_check_in_rhs.js b/packages/helpers/esm/_check_in_rhs.js new file mode 100644 index 000000000000..8e751e6ad2da --- /dev/null +++ b/packages/helpers/esm/_check_in_rhs.js @@ -0,0 +1,8 @@ +export function _check_in_rhs(value) { + if (Object(value) !== value) { + throw TypeError("right-hand side of 'in' should be an object, got " + (value !== null ? typeof value : "null")); + } + return value; +} + +export { _check_in_rhs as _ } \ No newline at end of file diff --git a/packages/helpers/esm/_set_function_name.js b/packages/helpers/esm/_set_function_name.js new file mode 100644 index 000000000000..369084d825e8 --- /dev/null +++ b/packages/helpers/esm/_set_function_name.js @@ -0,0 +1,15 @@ +export function _set_function_name(fn, name, prefix) { + if (typeof name === "symbol") { + name = name.description; + name = name ? "[" + name + "]" : ""; + } + try { + Object.defineProperty(fn, "name", { + configurable: true, + value: prefix ? prefix + " " + name : name + }); + } catch (_) { } + return fn; +} + +export { _set_function_name as _ } \ No newline at end of file