Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(es/decorators): Adjust implementation slightly based on version #9488

Draft
wants to merge 47 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
c62214f
API
kdy1 Aug 23, 2024
92043c2
Enable tests
kdy1 Aug 23, 2024
6d32baa
Add tests
kdy1 Aug 23, 2024
17333f0
helpers
kdy1 Aug 23, 2024
2b8a203
version
kdy1 Aug 23, 2024
e00b00d
More adjust
kdy1 Aug 23, 2024
c19ad85
state
kdy1 Aug 23, 2024
d55459e
create_set_function_name_call
kdy1 Aug 25, 2024
95270c5
fix build
kdy1 Aug 25, 2024
22d2deb
decoration args
kdy1 Aug 25, 2024
454bf4e
Update test refs for 2022-03
kdy1 Aug 26, 2024
7d535c0
args
kdy1 Aug 26, 2024
6d613be
ojbect pattern optimization
kdy1 Aug 26, 2024
7e5d317
Update test refs
kdy1 Aug 26, 2024
ea127be
Update test refs
kdy1 Aug 26, 2024
ee07621
cleanup: new_private()
kdy1 Aug 26, 2024
bfffa01
optimize computed prop name
kdy1 Aug 26, 2024
2cc1b91
Update test refs
kdy1 Aug 26, 2024
6842224
Optimize constants
kdy1 Aug 26, 2024
070f120
Rename
kdy1 Aug 26, 2024
95d01b0
Update test refs
kdy1 Aug 26, 2024
2cf3ea9
Update test refs matching babel
kdy1 Aug 26, 2024
ad0332b
Sync babel tests
kdy1 Aug 26, 2024
2212fed
init_extra
kdy1 Aug 26, 2024
17cb0fc
inject field inits
kdy1 Aug 26, 2024
4d904a6
swap to fix
kdy1 Aug 26, 2024
b92567d
Prefix with `_`
kdy1 Aug 26, 2024
2cb8261
Use identical prefix as babel
kdy1 Aug 26, 2024
2611968
Update test refs (trivial
kdy1 Aug 26, 2024
9596af3
Use correct logic for flags
kdy1 Aug 26, 2024
a86a37c
More flag fix
kdy1 Aug 26, 2024
3cf7dd4
to_property_key
kdy1 Aug 26, 2024
4f2db7b
this in init call
kdy1 Aug 26, 2024
7ad079d
Do not drop static_field_init_exprs
kdy1 Aug 26, 2024
61d4d1b
fix old decorators
kdy1 Aug 26, 2024
8df68bb
FIx `init_extra`
kdy1 Aug 26, 2024
2539f39
fix condition
kdy1 Aug 26, 2024
db1a4a6
Make condition more precise
kdy1 Aug 26, 2024
9ccc190
toPropertyKey
kdy1 Aug 28, 2024
732c847
Remove assumption test
kdy1 Aug 29, 2024
1bef533
Remove assumption test
kdy1 Aug 29, 2024
e71c0be
this_arg
kdy1 Aug 29, 2024
a217d09
Align var name with babel
kdy1 Aug 29, 2024
ae4af3a
Use this_arg
kdy1 Aug 29, 2024
6a26f36
visit_mut_class_decl: Ident
kdy1 Aug 29, 2024
77335cc
Make options.json parsing strict
kdy1 Oct 10, 2024
6a0ae91
Update
kdy1 Nov 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
239 changes: 239 additions & 0 deletions crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2311.js
Original file line number Diff line number Diff line change
@@ -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)
];
}
};
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
4 changes: 4 additions & 0 deletions crates/swc_ecma_transforms_base/src/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,10 @@ define_helpers!(Helpers {
dispose: (),
using: (),
using_ctx: (),

check_in_rhs: (),
set_function_name: (),
apply_decs_2311: (check_in_rhs, set_function_name, to_property_key),
});

pub fn inject_helpers(global_mark: Mark) -> impl Pass + VisitMut {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use swc_ecma_ast::Pass;

use crate::{decorator_impl::decorator_impl, DecoratorVersion};

pub fn decorator_2023_11() -> impl Pass {
decorator_impl(DecoratorVersion::V202311)
}
Loading
Loading