Skip to content

Commit

Permalink
feat(es/compat): Implement decorator metadata proposal (#8097)
Browse files Browse the repository at this point in the history
**Description:**

This PR implements the [decorator
metadata](https://github.com/tc39/proposal-decorator-metadata) proposal,
that is now at Stage 3.

As the decorator metadata proposal is a small extension of the decorator
proposal and is not possible to compile the metadata without transpiling
decorators, I opted to implement it into the existing decorator
transformer (and helper)

**Related issue:**

 - Closes #7957
  • Loading branch information
alekitto authored Oct 16, 2023
1 parent 7fe9c76 commit 9c029ef
Show file tree
Hide file tree
Showing 18 changed files with 226 additions and 89 deletions.
47 changes: 36 additions & 11 deletions crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function applyDecs2203RFactory() {
kind,
isStatic,
isPrivate,
metadata,
value
) {
var kindStr;
Expand All @@ -61,6 +62,7 @@ function applyDecs2203RFactory() {
name: isPrivate ? "#" + name : name,
static: isStatic,
private: isPrivate,
metadata: metadata,
};

var decoratorFinishedRef = { v: false };
Expand Down Expand Up @@ -168,7 +170,8 @@ function applyDecs2203RFactory() {
kind,
isStatic,
isPrivate,
initializers
initializers,
metadata
) {
var decs = decInfo[0];

Expand Down Expand Up @@ -221,6 +224,7 @@ function applyDecs2203RFactory() {
kind,
isStatic,
isPrivate,
metadata,
value
);

Expand Down Expand Up @@ -251,6 +255,7 @@ function applyDecs2203RFactory() {
kind,
isStatic,
isPrivate,
metadata,
value
);

Expand Down Expand Up @@ -345,7 +350,7 @@ function applyDecs2203RFactory() {
}
}

function applyMemberDecs(Class, decInfos) {
function applyMemberDecs(Class, decInfos, metadata) {
var ret = [];
var protoInitializers;
var staticInitializers;
Expand Down Expand Up @@ -415,7 +420,8 @@ function applyDecs2203RFactory() {
kind,
isStatic,
isPrivate,
initializers
initializers,
metadata
);
}

Expand All @@ -435,7 +441,7 @@ function applyDecs2203RFactory() {
}
}

function applyClassDecs(targetClass, classDecs) {
function applyClassDecs(targetClass, classDecs, metadata) {
if (classDecs.length > 0) {
var initializers = [];
var newClass = targetClass;
Expand All @@ -452,6 +458,7 @@ function applyDecs2203RFactory() {
initializers,
decoratorFinishedRef
),
metadata,
});
} finally {
decoratorFinishedRef.v = true;
Expand All @@ -464,7 +471,7 @@ function applyDecs2203RFactory() {
}

return [
newClass,
defineMetadata(newClass, metadata),
function () {
for (var i = 0; i < initializers.length; i++) {
initializers[i].call(newClass);
Expand All @@ -476,6 +483,14 @@ function applyDecs2203RFactory() {
// so we don't have to return an empty array here.
}

function defineMetadata(Class, metadata) {
return Object.defineProperty(
Class,
Symbol.metadata || Symbol.for("Symbol.metadata"),
{ configurable: true, enumerable: true, value: metadata }
);
}

/**
Basic usage:
Expand Down Expand Up @@ -622,21 +637,31 @@ function applyDecs2203RFactory() {
initializeClass(Class);
*/

return function applyDecs2203R(targetClass, memberDecs, classDecs) {
return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) {
if (parentClass !== void 0) {
var parentMetadata =
parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
}
var metadata = Object.create(
parentMetadata === void 0 ? null : parentMetadata
);
var e = applyMemberDecs(targetClass, memberDecs, metadata);
if (!classDecs.length) defineMetadata(targetClass, metadata);
return {
e: applyMemberDecs(targetClass, memberDecs),
e: e,
// Lazily apply class decorations so that member init locals can be properly bound.
get c() {
return applyClassDecs(targetClass, classDecs);
return applyClassDecs(targetClass, classDecs, metadata);
},
};
};
}

function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
return (_apply_decs_2203_r = applyDecs2203RFactory())(
targetClass,
memberDecs,
classDecs
classDecs,
parentClass
);
}
}
34 changes: 32 additions & 2 deletions crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ use swc_common::{util::take::Take, Spanned, SyntaxContext, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::{helper, helper_expr};
use swc_ecma_utils::{
constructor::inject_after_super, default_constructor, prepend_stmt, private_ident,
prop_name_to_expr_value, quote_ident, replace_ident, ExprFactory, IdentExt, IdentRenamer,
alias_ident_for, constructor::inject_after_super, default_constructor, prepend_stmt,
private_ident, prop_name_to_expr_value, quote_ident, replace_ident, ExprFactory, IdentExt,
IdentRenamer,
};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};

Expand Down Expand Up @@ -53,6 +54,8 @@ struct ClassState {

class_lhs: Vec<Option<Pat>>,
class_decorators: Vec<Option<ExprOrSpread>>,

super_class: Option<Ident>,
}

impl Decorator202203 {
Expand Down Expand Up @@ -154,6 +157,10 @@ impl Decorator202203 {
.as_arg(),
);

if let Some(super_class) = self.state.super_class.as_ref() {
combined_args.push(super_class.clone().as_arg());
}

let e_pat = if e_lhs.is_empty() {
None
} else {
Expand Down Expand Up @@ -323,6 +330,27 @@ impl Decorator202203 {
unreachable!()
}

fn handle_super_class(&mut self, class: &mut Class) {
if let Some(super_class) = class.super_class.take() {
let id = alias_ident_for(&super_class, "_super");
self.extra_vars.push(VarDeclarator {
span: DUMMY_SP,
name: Pat::Ident(id.clone().into()),
init: None,
definite: false,
});

class.super_class = Some(Box::new(Expr::Assign(AssignExpr {
span: DUMMY_SP,
op: AssignOp::Assign,
left: PatOrExpr::Pat(Box::new(Pat::Ident(id.clone().into()))),
right: super_class,
})));

self.state.super_class = Some(id);
}
}

fn handle_class_expr(&mut self, class: &mut Class, ident: Option<&Ident>) -> Ident {
debug_assert!(
!class.decorators.is_empty(),
Expand Down Expand Up @@ -361,6 +389,7 @@ impl Decorator202203 {

let decorators = self.preserve_side_effect_of_decorators(class.decorators.take());
self.state.class_decorators.extend(decorators);
self.handle_super_class(class);

{
let call_stmt = CallExpr {
Expand Down Expand Up @@ -417,6 +446,7 @@ impl Decorator202203 {
self.state.class_lhs.push(Some(init_class.clone().into()));

self.state.class_decorators.extend(decorators);
self.handle_super_class(&mut c.class);

let mut body = c.class.body.take();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var _A, __, __1, __2, _C, __3, __11, __21, _class, __4, __12, __22, _class1, __5, __13, __23, _G, __6, __14, __24, _class2, __7, __15, __25, _class3, __8, __16, __26, _K, __9, __17, __27;
var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _initClass7, _K1;
var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _I, _initClass7, _K1, _L;
const dec = ()=>{};
const A = ((_A = class A {
}, __ = {
Expand Down Expand Up @@ -81,25 +81,25 @@ const F = [
value: _initClass5()
}, _class2), _class6)
];
const H = ((_class3 = class extends I {
const H = ((_class3 = class extends (_I = I) {
}, __8 = {
writable: true,
value: { c: [_class7, _initClass6] } = _apply_decs_2203_r(_class3, [], [
dec
])
], _I)
}, __16 = {
writable: true,
value: (()=>{})()
}, __26 = {
writable: true,
value: _initClass6()
}, _class3), _class7);
const J = ((_K = class K extends L {
const J = ((_K = class K extends (_L = L) {
}, __9 = {
writable: true,
value: { c: [_K1, _initClass7] } = _apply_decs_2203_r(_K, [], [
dec
])
], _L)
}, __17 = {
writable: true,
value: (()=>{})()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var _A, __, __1, _C, __2, __11, _class, __3, __12, _class1, __4, __13, _G, __5, __14, _class2, __6, __15, _class3, __7, __16, _K, __8, __17;
var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _initClass7, _K1;
var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _I, _initClass7, _K1, _L;
const dec = ()=>{};
const A = ((_A = class A {
}, __ = {
Expand Down Expand Up @@ -63,22 +63,22 @@ const F = [
value: _initClass5()
}, _class2), _class6)
];
const H = ((_class3 = class extends I {
const H = ((_class3 = class extends (_I = I) {
}, __7 = {
writable: true,
value: { c: [_class7, _initClass6] } = _apply_decs_2203_r(_class3, [], [
dec
])
], _I)
}, __16 = {
writable: true,
value: _initClass6()
}, _class3), _class7);
const J = ((_K = class K extends L {
const J = ((_K = class K extends (_L = L) {
}, __8 = {
writable: true,
value: { c: [_K1, _initClass7] } = _apply_decs_2203_r(_K, [], [
dec
])
], _L)
}, __17 = {
writable: true,
value: _initClass7()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
var _initClass, _initClass1;
var _initClass, _initClass1, _Bar;
const dec1 = ()=>{};
const dec2 = ()=>{};
let _Bar;
let _Bar1;
class Bar {
}
var __ = {
writable: true,
value: { c: [_Bar, _initClass] } = _apply_decs_2203_r(Bar, [], [
value: { c: [_Bar1, _initClass] } = _apply_decs_2203_r(Bar, [], [
dec1
])
};
Expand All @@ -15,13 +15,13 @@ var __1 = {
value: _initClass()
};
let _Foo;
class Foo extends _Bar {
class Foo extends (_Bar = _Bar1) {
}
var __2 = {
writable: true,
value: { c: [_Foo, _initClass1] } = _apply_decs_2203_r(Foo, [], [
dec2
])
], _Bar)
};
var __11 = {
writable: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
var _class, __, _class1, __1;
var _initClass, _initClass1;
var _initClass, _initClass1, _Foo;
const dec = ()=>{};
let _Foo;
let _Foo1;
new (_class = class extends _identity {
constructor(){
super(_Foo), _initClass();
super(_Foo1), _initClass();
}
}, __ = {
writable: true,
Expand All @@ -13,7 +13,7 @@ new (_class = class extends _identity {
}
var __ = {
writable: true,
value: { c: [_Foo, _initClass] } = _apply_decs_2203_r(Foo, [], [
value: { c: [_Foo1, _initClass] } = _apply_decs_2203_r(Foo, [], [
dec
])
};
Expand All @@ -28,13 +28,14 @@ new (_class1 = class extends _identity {
}, __1 = {
writable: true,
value: (()=>{
class Bar extends _Foo {
var _ref;
class Bar extends (_ref = _Foo = _Foo1) {
}
var __ = {
writable: true,
value: { c: [_Bar, _initClass1] } = _apply_decs_2203_r(Bar, [], [
dec
])
], _Foo)
};
_define_property(Bar, "field", ((()=>{
Bar.otherField = 456;
Expand Down
Loading

1 comment on commit 9c029ef

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 9c029ef Previous: fb81a36 Ratio
es/full/bugs-1 283897 ns/iter (± 2608) 287822 ns/iter (± 6426) 0.99
es/full/minify/libraries/antd 1405713046 ns/iter (± 17479456) 1401968362 ns/iter (± 11888127) 1.00
es/full/minify/libraries/d3 292289520 ns/iter (± 3787883) 296948759 ns/iter (± 2444667) 0.98
es/full/minify/libraries/echarts 1111042075 ns/iter (± 8702075) 1129992687 ns/iter (± 6388478) 0.98
es/full/minify/libraries/jquery 89088164 ns/iter (± 94808) 88726595 ns/iter (± 260285) 1.00
es/full/minify/libraries/lodash 104021978 ns/iter (± 1280473) 103737288 ns/iter (± 339625) 1.00
es/full/minify/libraries/moment 52606030 ns/iter (± 70125) 52141486 ns/iter (± 168090) 1.01
es/full/minify/libraries/react 18917498 ns/iter (± 65679) 18764891 ns/iter (± 40483) 1.01
es/full/minify/libraries/terser 230147015 ns/iter (± 1837158) 232302121 ns/iter (± 2877678) 0.99
es/full/minify/libraries/three 409076159 ns/iter (± 1942028) 412834407 ns/iter (± 2715800) 0.99
es/full/minify/libraries/typescript 2793791118 ns/iter (± 11879713) 2809513681 ns/iter (± 13033301) 0.99
es/full/minify/libraries/victory 603574678 ns/iter (± 9316934) 603199352 ns/iter (± 4997236) 1.00
es/full/minify/libraries/vue 126889959 ns/iter (± 3066942) 126433142 ns/iter (± 564432) 1.00
es/full/codegen/es3 33732 ns/iter (± 81) 33545 ns/iter (± 90) 1.01
es/full/codegen/es5 33809 ns/iter (± 91) 33708 ns/iter (± 53) 1.00
es/full/codegen/es2015 33783 ns/iter (± 65) 33744 ns/iter (± 167) 1.00
es/full/codegen/es2016 33832 ns/iter (± 71) 33628 ns/iter (± 89) 1.01
es/full/codegen/es2017 33792 ns/iter (± 75) 33789 ns/iter (± 72) 1.00
es/full/codegen/es2018 33724 ns/iter (± 71) 33809 ns/iter (± 146) 1.00
es/full/codegen/es2019 33856 ns/iter (± 233) 33763 ns/iter (± 65) 1.00
es/full/codegen/es2020 33778 ns/iter (± 68) 33683 ns/iter (± 86) 1.00
es/full/all/es3 176572924 ns/iter (± 1886235) 175859848 ns/iter (± 569821) 1.00
es/full/all/es5 168512109 ns/iter (± 1657167) 169627433 ns/iter (± 1065745) 0.99
es/full/all/es2015 128041057 ns/iter (± 685885) 128372943 ns/iter (± 917145) 1.00
es/full/all/es2016 127199210 ns/iter (± 673867) 128281273 ns/iter (± 772794) 0.99
es/full/all/es2017 126589345 ns/iter (± 1052680) 127147539 ns/iter (± 776226) 1.00
es/full/all/es2018 124429928 ns/iter (± 721411) 125152360 ns/iter (± 1349576) 0.99
es/full/all/es2019 123913798 ns/iter (± 762048) 123736848 ns/iter (± 601171) 1.00
es/full/all/es2020 120298767 ns/iter (± 660412) 120386269 ns/iter (± 1326072) 1.00
es/full/parser 562676 ns/iter (± 2390) 562959 ns/iter (± 4290) 1.00
es/full/base/fixer 18503 ns/iter (± 164) 17712 ns/iter (± 61) 1.04
es/full/base/resolver_and_hygiene 83236 ns/iter (± 174) 83610 ns/iter (± 92) 1.00

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.