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

Fix 2021-12 decorators application order #14244

Merged
merged 15 commits into from Feb 8, 2022
Merged
@@ -1,4 +1,4 @@
import type { NodePath } from "@babel/traverse";
import type { NodePath, Scope } from "@babel/traverse";
import { types as t, template } from "@babel/core";
import syntaxDecorators from "@babel/plugin-syntax-decorators";
import ReplaceSupers from "@babel/helper-replace-supers";
Expand Down Expand Up @@ -506,13 +506,20 @@ function transformClass(
let constructorPath: NodePath<t.ClassMethod> | undefined;
let requiresProtoInit = false;
let requiresStaticInit = false;
let hasComputedProps = false;
const decoratedPrivateMethods = new Set<string>();

let protoInitLocal: t.Identifier,
staticInitLocal: t.Identifier,
classInitLocal: t.Identifier,
classLocal: t.Identifier;
const assignments: t.AssignmentExpression[] = [];
const scopeParent: Scope = path.scope.parent;

const memoiseExpression = (expression: t.Expression, hint: string) => {
const localEvaluatedId = scopeParent.generateDeclaredUidIdentifier(hint);
assignments.push(t.assignmentExpression("=", localEvaluatedId, expression));
return t.cloneNode(localEvaluatedId);
};

if (classDecorators) {
classInitLocal =
Expand All @@ -523,6 +530,15 @@ function transformClass(
classLocal = localId;

path.node.decorators = null;

for (const classDecorator of classDecorators) {
if (!scopeParent.isStatic(classDecorator.expression)) {
classDecorator.expression = memoiseExpression(
classDecorator.expression,
"dec",
);
}
}
} else {
if (!path.node.id) {
path.node.id = path.scope.generateUidIdentifier("Class");
Expand All @@ -536,43 +552,50 @@ function transformClass(
continue;
}

let { key } = element.node;
const kind = getElementKind(element);
const { node } = element;
const decorators = element.get("decorators");

const isPrivate = key.type === "PrivateName";
const hasDecorators = Array.isArray(decorators) && decorators.length > 0;

if (hasDecorators) {
for (const decoratorPath of decorators) {
if (!scopeParent.isStatic(decoratorPath.node.expression)) {
decoratorPath.node.expression = memoiseExpression(
decoratorPath.node.expression,
"dec",
);
}
}
}

const isComputed =
"computed" in element.node && element.node.computed === true;
if (isComputed) {
if (!scopeParent.isStatic(node.key)) {
node.key = memoiseExpression(node.key as t.Expression, "computedKey");
}
}

const kind = getElementKind(element);
const { key } = node;

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

const isStatic = !!element.node.static;

let name = "computedKey";

if (isPrivate) {
name = (key as t.PrivateName).id.name;
} else if (key.type === "Identifier") {
} else if (!isComputed && key.type === "Identifier") {
name = key.name;
}

if (element.isClassMethod({ kind: "constructor" })) {
constructorPath = element;
}

if (isComputed) {
const keyPath = element.get("key");
const localComputedNameId =
keyPath.scope.parent.generateDeclaredUidIdentifier(name);
keyPath.replaceWith(localComputedNameId);

elementDecoratorInfo.push({
localComputedNameId: t.cloneNode(localComputedNameId),
keyNode: t.cloneNode(key as t.Expression),
});

key = localComputedNameId;
hasComputedProps = true;
}

if (Array.isArray(decorators) && decorators.length > 0) {
if (hasDecorators) {
let locals: t.Identifier | t.Identifier[];
let privateMethods: t.FunctionExpression | t.FunctionExpression[];

Expand Down Expand Up @@ -730,33 +753,7 @@ function transformClass(
}
}

if (hasComputedProps) {
const assignments: t.AssignmentExpression[] = [];

for (const info of elementDecoratorInfo) {
if (isDecoratorInfo(info)) {
const { decorators } = info;
const newDecorators: t.Identifier[] = [];

for (const decorator of decorators) {
const localComputedNameId =
path.scope.parent.generateDeclaredUidIdentifier("dec");
assignments.push(
t.assignmentExpression("=", localComputedNameId, decorator),
);
newDecorators.push(t.cloneNode(localComputedNameId));
}

info.decorators = newDecorators;
} else {
assignments.push(
t.assignmentExpression("=", info.localComputedNameId, info.keyNode),
);
}
}

path.insertBefore(assignments);
}
path.insertBefore(assignments);

const elementDecorations = generateDecorationExprs(elementDecoratorInfo);
const classDecorations = t.arrayExpression(
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
@dec
accessor #a;
Expand Down
@@ -1,5 +1,7 @@
var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto;

const dec = () => {};

var _A = /*#__PURE__*/new WeakMap();

var _a = /*#__PURE__*/new WeakMap();
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
@dec
accessor a;
Expand Down
@@ -1,9 +1,8 @@
var _init_a, _init_b, _computedKey, _init_computedKey, _dec, _dec2, _dec3, _initProto;
var _init_a, _init_b, _computedKey, _init_computedKey, _initProto;

const dec = () => {};

_dec = dec
_dec2 = dec
_computedKey = 'c'
_dec3 = dec

var _A = /*#__PURE__*/new WeakMap();

Expand Down Expand Up @@ -54,5 +53,5 @@ class Foo {
}

(() => {
[_init_a, _init_b, _init_computedKey, _initProto] = babelHelpers.applyDecs(Foo, [[_dec, 1, "a"], [_dec2, 1, "b"], [_dec3, 1, _computedKey]], []);
[_init_a, _init_b, _init_computedKey, _initProto] = babelHelpers.applyDecs(Foo, [[dec, 1, "a"], [dec, 1, "b"], [dec, 1, _computedKey]], []);
})();
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
@dec
static accessor #a;
Expand Down
@@ -1,5 +1,7 @@
var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initStatic;

const dec = () => {};

var _a = /*#__PURE__*/new WeakMap();

var _b = /*#__PURE__*/new WeakMap();
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
@dec
static accessor a;
Expand Down
@@ -1,9 +1,8 @@
var _init_a, _init_b, _computedKey, _init_computedKey, _dec, _dec2, _dec3, _initStatic;
var _init_a, _init_b, _computedKey, _init_computedKey, _initStatic;

const dec = () => {};

_dec = dec
_dec2 = dec
_computedKey = 'c'
_dec3 = dec

class Foo {
static get a() {
Expand Down Expand Up @@ -33,7 +32,7 @@ class Foo {
}

(() => {
[_init_a, _init_b, _init_computedKey, _initStatic] = babelHelpers.applyDecs(Foo, [[_dec, 6, "a"], [_dec2, 6, "b"], [_dec3, 6, _computedKey]], []);
[_init_a, _init_b, _init_computedKey, _initStatic] = babelHelpers.applyDecs(Foo, [[dec, 6, "a"], [dec, 6, "b"], [dec, 6, _computedKey]], []);

_initStatic(Foo);
})();
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
accessor #a;

Expand Down
@@ -1,3 +1,5 @@
const dec = () => {};

var _A = /*#__PURE__*/new WeakMap();

var _a = /*#__PURE__*/new WeakMap();
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
accessor a;

Expand Down
@@ -1,3 +1,5 @@
const dec = () => {};

var _A = /*#__PURE__*/new WeakMap();

var _B = /*#__PURE__*/new WeakMap();
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
static accessor #a;

Expand Down
@@ -1,3 +1,5 @@
const dec = () => {};

class Foo {}

function _get_a() {
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
static accessor a;

Expand Down
@@ -1,3 +1,5 @@
const dec = () => {};

class Foo {
static get a() {
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _A);
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
@dec
accessor #a;
Expand Down
@@ -1,5 +1,7 @@
var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto;

const dec = () => {};

class Foo {
static {
[_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto] = babelHelpers.applyDecs(this, [[dec, 1, "a", function () {
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
@dec
accessor a;
Expand Down
@@ -1,13 +1,12 @@
var _init_a, _init_b, _computedKey, _init_computedKey, _dec, _dec2, _dec3, _initProto;
var _init_a, _init_b, _computedKey, _init_computedKey, _initProto;

const dec = () => {};

_dec = dec
_dec2 = dec
_computedKey = 'c'
_dec3 = dec

class Foo {
static {
[_init_a, _init_b, _init_computedKey, _initProto] = babelHelpers.applyDecs(this, [[_dec, 1, "a"], [_dec2, 1, "b"], [_dec3, 1, _computedKey]], []);
[_init_a, _init_b, _init_computedKey, _initProto] = babelHelpers.applyDecs(this, [[dec, 1, "a"], [dec, 1, "b"], [dec, 1, _computedKey]], []);
}
#A = (_initProto(this), _init_a(this));

Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
@dec
static accessor #a;
Expand Down
@@ -1,5 +1,7 @@
var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initStatic;

const dec = () => {};

class Foo {
static {
[_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initStatic] = babelHelpers.applyDecs(this, [[dec, 6, "a", function () {
Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
@dec
static accessor a;
Expand Down
@@ -1,13 +1,12 @@
var _init_a, _init_b, _computedKey, _init_computedKey, _dec, _dec2, _dec3, _initStatic;
var _init_a, _init_b, _computedKey, _init_computedKey, _initStatic;

const dec = () => {};

_dec = dec
_dec2 = dec
_computedKey = 'c'
_dec3 = dec

class Foo {
static {
[_init_a, _init_b, _init_computedKey, _initStatic] = babelHelpers.applyDecs(this, [[_dec, 6, "a"], [_dec2, 6, "b"], [_dec3, 6, _computedKey]], []);
[_init_a, _init_b, _init_computedKey, _initStatic] = babelHelpers.applyDecs(this, [[dec, 6, "a"], [dec, 6, "b"], [dec, 6, _computedKey]], []);

_initStatic(this);

Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
accessor #a;

Expand Down
@@ -1,3 +1,5 @@
const dec = () => {};

class Foo {
#A;

Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
accessor a;

Expand Down
@@ -1,3 +1,5 @@
const dec = () => {};

class Foo {
#A;

Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
static accessor #a;

Expand Down
@@ -1,3 +1,5 @@
const dec = () => {};

class Foo {
static #A;

Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
class Foo {
static accessor a;

Expand Down
@@ -1,3 +1,5 @@
const dec = () => {};

class Foo {
static #A;

Expand Down
@@ -1,3 +1,4 @@
const dec = () => {};
@dec
class Foo extends Bar {
constructor() {
Expand Down