diff --git a/crates/swc/src/config/mod.rs b/crates/swc/src/config/mod.rs index 9a826a9a88e6..0b7a911619a7 100644 --- a/crates/swc/src/config/mod.rs +++ b/crates/swc/src/config/mod.rs @@ -687,7 +687,9 @@ impl Options { DecoratorVersion::V202203 => Box::new( swc_ecma_transforms::proposals::decorator_2022_03::decorator_2022_03(), ), - DecoratorVersion::V202311 => todo!("2023-11 decorator"), + DecoratorVersion::V202311 => Box::new( + swc_ecma_transforms::proposals::decorator_2023_11::decorator_2023_11(), + ), }; Box::new(chain!( 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 7720369d2ea7..eec0846d0477 100644 --- a/crates/swc_ecma_transforms_base/src/helpers/mod.rs +++ b/crates/swc_ecma_transforms_base/src/helpers/mod.rs @@ -411,6 +411,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 Fold + 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..9a8cc8f358b9 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/src/decorator_2023_11.rs @@ -0,0 +1,7 @@ +use swc_ecma_visit::{Fold, VisitMut}; + +use crate::decorator_impl::decorator_impl; + +pub fn decorator_2023_11() -> impl VisitMut + Fold { + decorator_impl(crate::DecoratorVersion::V202311) +} diff --git a/crates/swc_ecma_transforms_proposal/src/decorator_pass.rs b/crates/swc_ecma_transforms_proposal/src/decorator_pass.rs new file mode 100644 index 000000000000..b376020666ff --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/src/decorator_pass.rs @@ -0,0 +1,224 @@ +use std::mem::take; + +use rustc_hash::FxHashSet; +use swc_common::DUMMY_SP; +use swc_ecma_ast::*; +use swc_ecma_utils::private_ident; +use swc_ecma_visit::{as_folder, Fold, NodeRef, VisitMut, VisitMutWith}; + +use crate::DecoratorVersion; + +#[allow(unused)] +pub(crate) fn decorator_pass(version: DecoratorVersion) -> impl Fold + VisitMut { + as_folder(DecoratorPass { + version, + state: Default::default(), + }) +} + +struct DecoratorPass { + version: DecoratorVersion, + state: State, +} + +#[derive(Default)] +struct State { + class: ClassState, +} + +#[derive(Default)] +struct ClassState { + class_id_name: Option, + + has_element_decorators: bool, + has_computed_keys_side_effects: bool, + elem_decs_use_fn_context: bool, + + class_assignments: Vec, + + proto_init_local: Ident, + static_init_local: Ident, + + instance_private_names: Vec, +} + +impl ClassState { + fn memoize_expr(&mut self, expr: Box, hint: &str, assignments: &mut Vec) {} +} + +impl DecoratorPass { + fn transform_class(&mut self, class_name: Option, class: &mut Class) { + let old_state = take(&mut self.state.class); + + let class_decorators = take(&mut class.decorators); + + // Iterate over the class to see if we need to decorate it, and also to + // transform simple auto accessors which are not decorated, and handle inferred + // class name when the initializer of the class field is a class expression + + for el in class.body.iter_mut() { + if !is_class_decoratable_element_path(el) { + continue; + } + + if !el.is_static() { + if let Key::Private(name) = el.key { + self.state.instance_private_names.push(name); + } + } + + if let Some(decorators) = decorators_of(el) { + match el { + ClassMember::ClassProp(prop) => { + prop.visit_mut_with(&mut PropertyVisitor {}); + } + ClassMember::PrivateProp(prop) => { + prop.visit_mut_with(&mut PropertyVisitor {}); + } + + ClassMember::AutoAccessor(accessor) => { + accessor.visit_mut_with(&mut PropertyVisitor {}); + + match self.version { + DecoratorVersion::V202311 => {} + _ => { + if accessor.is_static { + self.state.class.static_init_local = + Ident::new_private("initStatic".into(), DUMMY_SP); + } else { + self.state.class.proto_init_local = + Ident::new_private("initProto".into(), DUMMY_SP); + } + } + } + } + + _ => {} + } + + self.state.class.has_element_decorators = true; + if !self.state.class.elem_decs_use_fn_context { + self.state.class.elem_decs_use_fn_context |= decorators + .iter() + .any(|d| self.state.class.uses_function_context_or_yield_await(d)) + } + } else if let ClassMember::AutoAccessor(accesssor) = el { + let is_static = accesssor.is_static; + + let new_id = generate_class_private_uid(); + let new_field = generate_class_property(new_id, accesssor.value, is_static); + + let mut getter_key; + let mut setter_key; + + match accesssor.key { + Key::Public(PropName::Computed(key)) => { + getter_key = memoise_computed_key( + create_to_property_key_call(state, key), + private_ident!("computedKey"), + ); + } + _ => { + getter_key = accesssor.key.clone(); + setter_key = take(&mut accesssor.key); + } + } + + assign_id_for_anonymous_class(path, class_name); + + add_proxy_accessor_for(getter_key, setter_key, new_field, is_static); + } + + if is_computed { + self.state.class.has_computed_keys_side_effects |= !is_static; + } + } + + if class_decorators.is_empty() && !self.state.class.has_element_decorators { + // TODO: + // path.node.body.body.unshift( + // createStaticBlockFromExpressions([ + // createSetFunctionNameCall(state, setClassName), + // ]), + // ); + + // If nothing is decorated and no assignments inserted, return + return; + } + + let element_decorator_info = vec![]; + let mut decorated_private_methods = FxHashSet::::default(); + + let mut class_init_local = None; + let mut class_id_local = None; + + let mut decorator_receiver_id = None; + + let will_extract_some_element_decorators = has_computed_keys_side_effects; + + let needs_declration_for_class_binding = false; + let class_decorations_flag = 0; + let class_decorations = Vec::>::new(); + let mut class_decorations_id: Option = None; + let mut computed_key_assignments = Vec::::new(); + + if !class_decorators.is_empty() { + class_init_local = generate_uid_identifier("initClass") + } + + self.state.class = old_state; + } + + /// Ported from `handleDecorators` at https://github.com/babel/babel/blob/440fe413330f19fdb2c5fa63ffab87e67383d12d/packages/babel-helper-create-class-features-plugin/src/decorators.ts#L1225-L1255 + fn handle_decorators(&mut self, dec: Vec) -> HandleDecoratorsResult {} +} + +impl VisitMut for DecoratorPass { + fn visit_mut_class_decl(&mut self, node: &mut ClassDecl) { + self.transform_class(Some(node.ident.clone()), &mut node.class); + } + + fn visit_mut_class_expr(&mut self, node: &mut ClassExpr) { + self.transform_class(node.ident.clone(), &mut node.class); + } +} + +impl ClassState { + fn uses_function_context_or_yield_await(&self, dec: &Decorator) -> bool { + let nr = NodeRef::from(dec); + let mut iter = nr.experimental_traverse(); + + iter.any(|n| match n { + NodeRef::ThisExpr(..) + | NodeRef::Super(..) + | NodeRef::AwaitExpr(..) + | NodeRef::YieldExpr(..) + | NodeRef::MetaPropKind(MetaPropKind::NewTarget) => true, + + NodeRef::Ident(i) => { + if i.sym == "arguments" { + return true; + } + + if self.class_id_name == Some(i.to_id()) { + return true; + } + + false + } + + _ => false, + }) + } +} + +struct HandleDecoratorsResult { + has_side_effects: bool, + uses_fn_context: bool, + + decorator_this: Vec>>, +} + +struct PropertyVisitor {} + +impl VisitMut for PropertyVisitor {} diff --git a/crates/swc_ecma_transforms_proposal/src/lib.rs b/crates/swc_ecma_transforms_proposal/src/lib.rs index 58ed23fb9eb5..29f30adaed45 100644 --- a/crates/swc_ecma_transforms_proposal/src/lib.rs +++ b/crates/swc_ecma_transforms_proposal/src/lib.rs @@ -1,4 +1,5 @@ #![deny(clippy::all)] +#![allow(clippy::boxed_local)] #![allow(clippy::vec_box)] use serde::{Deserialize, Serialize}; @@ -23,7 +24,9 @@ pub enum DecoratorVersion { } pub mod decorator_2022_03; +pub mod decorator_2023_11; mod decorator_impl; +mod decorator_pass; pub mod decorators; pub mod explicit_resource_management; mod export_default_from; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorator_evanw.rs b/crates/swc_ecma_transforms_proposal/tests/decorator_evanw.rs index d077a1c645f4..bd79ce8be5d5 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; use swc_ecma_visit::as_folder; @@ -64,7 +64,7 @@ fn fixture(input: PathBuf) { auto_accessors: true, ..Default::default() }), - |_| as_folder(decorator_2022_03()), + |_| as_folder(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 aec96d387679..150cdb06e7ef 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators.rs +++ b/crates/swc_ecma_transforms_proposal/tests/decorators.rs @@ -9,7 +9,9 @@ use serde::Deserialize; use swc_common::{chain, comments::SingleThreadedComments, Mark}; 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; @@ -163,7 +165,7 @@ fn create_pass(comments: Rc, input: &Path) -> Box 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/.2023-11-assumption-constantSuper/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/options.json new file mode 100644 index 000000000000..34484ba02297 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [["proposal-decorators", { "version": "2023-11" }]], + "assumptions": { + "constantSuper": true + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-nested-constructor-expression/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-nested-constructor-expression/input.js new file mode 100644 index 000000000000..6bc1a7dbbc4b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-nested-constructor-expression/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +@dec +class Foo extends Bar { + constructor() { + let foo = super(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-nested-constructor-expression/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/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-assumption-constantSuper/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/.2023-11-assumption-constantSuper/super-in-private-accessor/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-private-accessor/input.js new file mode 100644 index 000000000000..b32ea0bd378f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-private-accessor/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +class Foo extends Bar { + @dec + get #x() { + return super.foo(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-private-accessor/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-private-accessor/output.js new file mode 100644 index 000000000000..774bfae1280d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/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 Bar.prototype.foo.call(this); + }]], 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/.2023-11-assumption-constantSuper/super-in-private-method/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-private-method/input.js new file mode 100644 index 000000000000..36f9bd37dfa7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-private-method/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +class Foo extends Bar { + @dec + #x() { + return super.foo(); + } +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-private-method/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/super-in-private-method/output.js new file mode 100644 index 000000000000..2803ba01e83e --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/.2023-11-assumption-constantSuper/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 Bar.prototype.foo.call(this); + }]], 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-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..62724b00452e --- /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..10a776ffc566 --- /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..b3a96356f951 --- /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..4ac431dd7fdb --- /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..1739d69e40e0 --- /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..5582a296c33f --- /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.get(babelHelpers.getPrototypeOf(_Foo), "id", this).call(this, 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..a32d3979e16b --- /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.get(babelHelpers.getPrototypeOf(_Foo), "id", this).call(this, 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..a42d262d090d --- /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..214b959b2b7c --- /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..f26e2b9c8f8c --- /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..7fd8911942c5 --- /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..3e47d2b1705a --- /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..d3ff9bd59b79 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-fields/output.js @@ -0,0 +1,28 @@ +var _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] } = _apply_decs_2311(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..d7a0c76e7bc1 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-classes/decorator-access-modified-methods/output.js @@ -0,0 +1,28 @@ +var _initClass, _initProto; +var value; +const classDec = (Class)=>{ + value = (new Class).m(); + return Class; +}; +const memberDec = ()=>()=>42; +let _C; +class C { + static{ + ({ e: [_initProto], c: [_C, _initClass] } = _apply_decs_2311(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..0473cbe1a30d --- /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..f69867b0893b --- /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..4ff4e6a51a1f --- /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.get(babelHelpers.getPrototypeOf(_Foo), "id", this).call(this, 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..326dd6f0bf4f --- /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.get(babelHelpers.getPrototypeOf(_Foo), "id", this).call(this, 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..6270a41f708b --- /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..faf300be505c --- /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..8ebec6895582 --- /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..2116c6cfe966 --- /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..c76a7cff262e --- /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..2223722831e3 --- /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..2f83e25a77bc --- /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/2023-11-misc/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 new file mode 100644 index 000000000000..6bc1a7dbbc4b --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-nested-constructor-expression/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +@dec +class Foo extends Bar { + constructor() { + let foo = super(); + } +} 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/2023-11-misc/super-in-private-accessor/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-accessor/input.js new file mode 100644 index 000000000000..b32ea0bd378f --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-accessor/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +class Foo extends Bar { + @dec + get #x() { + return super.foo(); + } +} 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..264cd6ea3c81 --- /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.get(babelHelpers.getPrototypeOf(Foo), "foo", this).call(this); + }]], 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/2023-11-misc/super-in-private-method/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-method/input.js new file mode 100644 index 000000000000..36f9bd37dfa7 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2023-11-misc/super-in-private-method/input.js @@ -0,0 +1,7 @@ +const dec = () => {}; +class Foo extends Bar { + @dec + #x() { + return super.foo(); + } +} 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..7b6bdb1dc474 --- /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.get(babelHelpers.getPrototypeOf(Foo), "foo", this).call(this); + }]], 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..b88df6f19888 --- /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..232e7e3e6377 --- /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