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

Improve temporary variables for decorators #16218

Merged
merged 2 commits into from Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
115 changes: 68 additions & 47 deletions packages/babel-helper-create-class-features-plugin/src/decorators.ts
Expand Up @@ -562,7 +562,7 @@ function transformClass(
continue;
}

if (element.node.decorators && element.node.decorators.length > 0) {
if (element.node.decorators?.length) {
switch (element.node.type) {
case "ClassProperty":
// @ts-expect-error todo: propertyVisitor.ClassProperty should be callable. Improve typings.
Expand Down Expand Up @@ -646,38 +646,72 @@ function transformClass(
classIdLocal: t.Identifier;

const decoratorsThis = new Map<t.Decorator, t.Expression>();
const maybeExtractDecorator = (decorator: t.Decorator) => {
const { expression } = decorator;
if (version === "2023-05" && t.isMemberExpression(expression)) {
let object;
if (
t.isSuper(expression.object) ||
t.isThisExpression(expression.object)
) {
object = memoiseExpression(t.thisExpression(), "obj");
} else if (!scopeParent.isStatic(expression.object)) {
object = memoiseExpression(expression.object, "obj");
expression.object = object;
} else {
object = expression.object;
const maybeExtractDecorators = (
decorators: t.Decorator[],
memoiseInPlace: boolean,
) => {
let needMemoise = false;
for (const decorator of decorators) {
const { expression } = decorator;
if (version === "2023-05" && t.isMemberExpression(expression)) {
let object;
if (
t.isSuper(expression.object) ||
t.isThisExpression(expression.object)
) {
needMemoise = true;
if (memoiseInPlace) {
object = memoiseExpression(t.thisExpression(), "obj");
} else {
object = t.thisExpression();
}
} else {
if (!scopeParent.isStatic(expression.object)) {
needMemoise = true;
if (memoiseInPlace) {
expression.object = memoiseExpression(expression.object, "obj");
}
}
object = t.cloneNode(expression.object);
}
decoratorsThis.set(decorator, object);
}
if (!scopeParent.isStatic(expression)) {
needMemoise = true;
if (memoiseInPlace) {
decorator.expression = memoiseExpression(expression, "dec");
}
}
decoratorsThis.set(decorator, t.cloneNode(object));
}
if (!scopeParent.isStatic(expression)) {
decorator.expression = memoiseExpression(expression, "dec");
}
return needMemoise && !memoiseInPlace;
};

let needsDeclaraionForClassBinding = false;
let classDecorationsFlag = 0;
let classDecorations: t.Expression[] = [];
let classDecorationsId: t.Identifier;
if (classDecorators) {
classInitLocal = scopeParent.generateDeclaredUidIdentifier("initClass");
needsDeclaraionForClassBinding = path.isClassDeclaration();
({ id: classIdLocal, path } = replaceClassWithVar(path, className));

path.node.decorators = null;

for (const classDecorator of classDecorators) {
maybeExtractDecorator(classDecorator);
const needMemoise = maybeExtractDecorators(classDecorators, false);

const { hasThis, decs } = generateDecorationList(
classDecorators.map(el => el.expression),
classDecorators.map(dec => decoratorsThis.get(dec)),
version,
);
classDecorationsFlag = hasThis ? 1 : 0;
classDecorations = decs;

if (needMemoise) {
classDecorationsId = memoiseExpression(
t.arrayExpression(classDecorations),
"classDecs",
);
}
} else {
if (!path.node.id) {
Expand All @@ -696,18 +730,15 @@ function transformClass(
}

const { node } = element;
const decorators = element.get("decorators");
const decorators = element.node.decorators;

const hasDecorators = Array.isArray(decorators) && decorators.length > 0;
const hasDecorators = !!decorators?.length;

if (hasDecorators) {
for (const decoratorPath of decorators) {
maybeExtractDecorator(decoratorPath.node);
}
maybeExtractDecorators(decorators, true);
}

const isComputed =
"computed" in element.node && element.node.computed === true;
const isComputed = "computed" in element.node && element.node.computed;
if (isComputed) {
if (!element.get("key").isConstantExpression()) {
node.key = memoiseExpression(
Expand All @@ -722,7 +753,7 @@ function transformClass(

const isPrivate = key.type === "PrivateName";

const isStatic = !!element.node.static;
const isStatic = element.node.static;

let name = "computedKey";

Expand Down Expand Up @@ -881,8 +912,8 @@ function transformClass(

elementDecoratorInfo.push({
kind,
decorators: decorators.map(d => d.node.expression),
decoratorsThis: decorators.map(d => decoratorsThis.get(d.node)),
decorators: decorators.map(d => d.expression),
decoratorsThis: decorators.map(d => decoratorsThis.get(d)),
name: nameExpr,
isStatic,
privateMethods,
Expand Down Expand Up @@ -918,17 +949,6 @@ function transformClass(
elementDecoratorInfo,
version,
);
let classDecorationsFlag = 0;
let classDecorations: t.Expression[] = [];
if (classDecorators) {
const { hasThis, decs } = generateDecorationList(
classDecorators.map(el => el.expression),
classDecorators.map(dec => decoratorsThis.get(dec)),
version,
);
classDecorationsFlag = hasThis ? 1 : 0;
classDecorations = decs;
}

const elementLocals: t.Identifier[] =
extractElementLocalAssignments(elementDecoratorInfo);
Expand Down Expand Up @@ -992,7 +1012,7 @@ function transformClass(
t.classMethod(
"constructor",
t.identifier("constructor"),
[t.restElement(t.identifier("args"))],
path.node.superClass ? [t.restElement(t.identifier("args"))] : [],
t.blockStatement(body),
),
);
Expand Down Expand Up @@ -1143,7 +1163,6 @@ function transformClass(
superClass = id;
}
}

originalClass.body.body.unshift(
t.staticBlock(
[
Expand All @@ -1152,7 +1171,9 @@ function transformClass(
elementLocals,
classLocals,
elementDecorations,
t.arrayExpression(classDecorations),
classDecorationsId
? t.cloneNode(classDecorationsId)
: t.arrayExpression(classDecorations),
t.numericLiteral(classDecorationsFlag),
needsInstancePrivateBrandCheck ? lastInstancePrivateName : null,
typeof className === "object" ? className : undefined,
Expand Down Expand Up @@ -1192,8 +1213,8 @@ function transformClass(
function createLocalsAssignment(
elementLocals: t.Identifier[],
classLocals: t.Identifier[],
elementDecorations: t.ArrayExpression,
classDecorations: t.ArrayExpression,
elementDecorations: t.ArrayExpression | t.Identifier,
classDecorations: t.ArrayExpression | t.Identifier,
classDecorationsFlag: t.NumericLiteral,
maybePrivateBranName: t.PrivateName | null,
setClassName: t.Identifier | t.StringLiteral | undefined,
Expand Down
Expand Up @@ -1110,7 +1110,8 @@ export function buildFieldsInitNodes(
};

const classRefForInnerBinding =
ref ?? props[0].scope.generateUidIdentifier("class");
ref ??
props[0].scope.generateUidIdentifier(innerBindingRef?.name || "Class");
ref ??= t.cloneNode(innerBindingRef);

for (const prop of props) {
Expand Down
Expand Up @@ -230,7 +230,7 @@ export function createClassFeaturePlugin({
let ref: t.Identifier | null;
if (!innerBinding || !pathIsClassDeclaration) {
nameFunction(path);
ref = path.scope.generateUidIdentifier("class");
ref = path.scope.generateUidIdentifier(innerBinding?.name || "Class");
}
const classRefForDefine = ref ?? t.cloneNode(innerBinding);

Expand Down
@@ -1,13 +1,13 @@
var _class;
var _A;
var _foo = /*#__PURE__*/new WeakSet();
class A extends B {
constructor(...args) {
super(...args);
babelHelpers.classPrivateMethodInitSpec(this, _foo);
}
}
_class = A;
_A = A;
function _foo2() {
let _A;
babelHelpers.get(babelHelpers.getPrototypeOf(_class.prototype), "x", this);
let _A2;
babelHelpers.get(babelHelpers.getPrototypeOf(_A.prototype), "x", this);
}
@@ -1,11 +1,11 @@
export default babelHelpers.decorate([dec()], function (_initialize) {
class _class {
class _Class {
constructor() {
_initialize(this);
}
}
return {
F: _class,
F: _Class,
d: []
};
});
@@ -1,13 +1,13 @@
babelHelpers.decorate([dec()], function (_initialize) {
"use strict";

class _class {
class _Class {
constructor() {
_initialize(this);
}
}
return {
F: _class,
F: _Class,
d: []
};
});
@@ -1,4 +1,4 @@
var _init_a, _init_a2, _get_a, _set_a, _init_computedKey, _init_computedKey2, _init_computedKey3, _init_computedKey4, _init_computedKey5, _init_computedKey6, _computedKey, _init_computedKey7, _initStatic, _class;
var _init_a, _init_a2, _get_a, _set_a, _init_computedKey, _init_computedKey2, _init_computedKey3, _init_computedKey4, _init_computedKey5, _init_computedKey6, _computedKey, _init_computedKey7, _initStatic, _Foo;
const logs = [];
const dec = (value, context) => {
logs.push(context.name);
Expand Down Expand Up @@ -67,55 +67,55 @@ class Foo {
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _I, v);
}
}
_class = Foo;
_Foo = Foo;
function _set_a2(v) {
_set_a(this, v);
}
function _get_a2() {
return _get_a(this);
}
(() => {
[_init_a, _init_a2, _get_a, _set_a, _init_computedKey, _init_computedKey2, _init_computedKey3, _init_computedKey4, _init_computedKey5, _init_computedKey6, _init_computedKey7, _initStatic] = babelHelpers.applyDecs(_class, [[dec, 6, "a"], [dec, 6, "a", function () {
return babelHelpers.classStaticPrivateFieldSpecGet(this, _class, _B);
[_init_a, _init_a2, _get_a, _set_a, _init_computedKey, _init_computedKey2, _init_computedKey3, _init_computedKey4, _init_computedKey5, _init_computedKey6, _init_computedKey7, _initStatic] = babelHelpers.applyDecs(_Foo, [[dec, 6, "a"], [dec, 6, "a", function () {
return babelHelpers.classStaticPrivateFieldSpecGet(this, _Foo, _B);
}, function (value) {
babelHelpers.classStaticPrivateFieldSpecSet(this, _class, _B, value);
babelHelpers.classStaticPrivateFieldSpecSet(this, _Foo, _B, value);
}], [dec, 6, "b"], [dec, 6, "c"], [dec, 6, 0], [dec, 6, 1], [dec, 6, 2n], [dec, 6, 3n], [dec, 6, _computedKey]], []);
_initStatic(_class);
_initStatic(_Foo);
})();
var _A = {
writable: true,
value: _init_a(_class)
value: _init_a(_Foo)
};
var _B = {
writable: true,
value: _init_a2(_class)
value: _init_a2(_Foo)
};
var _C = {
writable: true,
value: _init_computedKey(_class)
value: _init_computedKey(_Foo)
};
var _D = {
writable: true,
value: _init_computedKey2(_class)
value: _init_computedKey2(_Foo)
};
var _E = {
writable: true,
value: _init_computedKey3(_class)
value: _init_computedKey3(_Foo)
};
var _F = {
writable: true,
value: _init_computedKey4(_class)
value: _init_computedKey4(_Foo)
};
var _G = {
writable: true,
value: _init_computedKey5(_class)
value: _init_computedKey5(_Foo)
};
var _H = {
writable: true,
value: _init_computedKey6(_class)
value: _init_computedKey6(_Foo)
};
var _I = {
writable: true,
value: _init_computedKey7(_class)
value: _init_computedKey7(_Foo)
};
expect(logs).toStrictEqual(["computing f", "calling toPrimitive", "a", "#a", "b", "c", "0", "1", "2", "3", "f()"]);
@@ -1,4 +1,4 @@
var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto, _class;
var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto, _Foo;
const dec = () => {};
var _A = /*#__PURE__*/new WeakMap();
var _a = /*#__PURE__*/new WeakMap();
Expand All @@ -24,7 +24,7 @@ class Foo {
});
}
}
_class = Foo;
_Foo = Foo;
function _set_a2(v) {
_set_a(this, v);
}
Expand All @@ -37,7 +37,7 @@ function _set_b2(v) {
function _get_b2() {
return _get_b(this);
}
[_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto] = babelHelpers.applyDecs(_class, [[dec, 1, "a", function () {
[_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto] = babelHelpers.applyDecs(_Foo, [[dec, 1, "a", function () {
return babelHelpers.classPrivateFieldGet(this, _A);
}, function (value) {
babelHelpers.classPrivateFieldSet(this, _A, value);
Expand Down
@@ -1,4 +1,4 @@
var _init_a, _init_b, _init_computedKey, _initProto, _class;
var _init_a, _init_b, _init_computedKey, _initProto, _Foo;
const dec = () => {};
var _A = /*#__PURE__*/new WeakMap();
var _B = /*#__PURE__*/new WeakMap();
Expand Down Expand Up @@ -37,5 +37,5 @@ class Foo {
babelHelpers.classPrivateFieldSet(this, _C, v);
}
}
_class = Foo;
[_init_a, _init_b, _init_computedKey, _initProto] = babelHelpers.applyDecs(_class, [[dec, 1, "a"], [dec, 1, "b"], [dec, 1, 'c']], []);
_Foo = Foo;
[_init_a, _init_b, _init_computedKey, _initProto] = babelHelpers.applyDecs(_Foo, [[dec, 1, "a"], [dec, 1, "b"], [dec, 1, 'c']], []);