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

Remove logic for deprecated decorator versions from Babel 8 #16256

Merged
merged 5 commits into from Feb 4, 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
Jump to file
Failed to load files.
Diff view
Diff view
164 changes: 88 additions & 76 deletions packages/babel-helper-create-class-features-plugin/src/decorators.ts
Expand Up @@ -187,7 +187,9 @@ function addProxyAccessorsFor(
const { static: isStatic } = element.node;

const thisArg =
(version === "2023-11" || version === "2023-05") && isStatic
(version === "2023-11" ||
(!process.env.BABEL_8_BREAKING && version === "2023-05")) &&
isStatic
? className
: t.thisExpression();

Expand Down Expand Up @@ -538,7 +540,11 @@ function generateDecorationList(
const hasOneThis = decoratorsThis.some(Boolean);
const decs: t.Expression[] = [];
for (let i = 0; i < decsCount; i++) {
if ((version === "2023-11" || version === "2023-05") && hasOneThis) {
if (
(version === "2023-11" ||
(!process.env.BABEL_8_BREAKING && version === "2023-05")) &&
hasOneThis
) {
decs.push(
decoratorsThis[i] || t.unaryExpression("void", t.numericLiteral(0)),
);
Expand All @@ -564,7 +570,8 @@ function generateDecorationExprs(
let flag = el.kind;
if (el.isStatic) {
flag +=
version === "2023-11" || version === "2023-05"
version === "2023-11" ||
(!process.env.BABEL_8_BREAKING && version === "2023-05")
? STATIC
: STATIC_OLD_VERSION;
}
Expand Down Expand Up @@ -716,6 +723,13 @@ function createToPropertyKeyCall(state: PluginPass, propertyKey: t.Expression) {
return t.callExpression(state.addHelper("toPropertyKey"), [propertyKey]);
}

function createPrivateBrandCheckClosure(brandName: t.PrivateName) {
return t.arrowFunctionExpression(
[t.identifier("_")],
t.binaryExpression("in", t.cloneNode(brandName), t.identifier("_")),
);
}

function checkPrivateMethodUpdateError(
path: NodePath<t.Class>,
decoratedPrivateMethods: Set<string>,
Expand Down Expand Up @@ -891,7 +905,8 @@ function transformClass(
for (const decorator of decorators) {
const { expression } = decorator;
if (
(version === "2023-11" || version === "2023-05") &&
(version === "2023-11" ||
(!process.env.BABEL_8_BREAKING && version === "2023-05")) &&
t.isMemberExpression(expression)
) {
let object;
Expand Down Expand Up @@ -963,27 +978,27 @@ function transformClass(
let lastInstancePrivateName: t.PrivateName;
let needsInstancePrivateBrandCheck = false;

let fieldInitializerAssignments = [];
let staticFieldInitializerAssignments = [];
let fieldInitializerExpressions = [];
let staticFieldInitializerExpressions: t.Expression[] = [];

if (hasElementDecorators) {
if (protoInitLocal) {
const protoInitCall = t.callExpression(t.cloneNode(protoInitLocal), [
t.thisExpression(),
]);
fieldInitializerAssignments.push(protoInitCall);
fieldInitializerExpressions.push(protoInitCall);
}
for (const element of body) {
if (!isClassDecoratableElementPath(element)) {
if (
staticFieldInitializerAssignments.length > 0 &&
staticFieldInitializerExpressions.length > 0 &&
element.isStaticBlock()
) {
prependExpressionsToStaticBlock(
staticFieldInitializerAssignments,
staticFieldInitializerExpressions,
element,
);
staticFieldInitializerAssignments = [];
staticFieldInitializerExpressions = [];
}
continue;
}
Expand Down Expand Up @@ -1186,27 +1201,27 @@ function transformClass(
}

if (
fieldInitializerAssignments.length > 0 &&
fieldInitializerExpressions.length > 0 &&
!isStatic &&
(kind === FIELD || kind === ACCESSOR)
) {
prependExpressionsToFieldInitializer(
fieldInitializerAssignments,
fieldInitializerExpressions,
element as NodePath<t.ClassProperty | t.ClassPrivateProperty>,
);
fieldInitializerAssignments = [];
fieldInitializerExpressions = [];
}

if (
staticFieldInitializerAssignments.length > 0 &&
staticFieldInitializerExpressions.length > 0 &&
isStatic &&
(kind === FIELD || kind === ACCESSOR)
) {
prependExpressionsToFieldInitializer(
staticFieldInitializerAssignments,
staticFieldInitializerExpressions,
element as NodePath<t.ClassProperty | t.ClassPrivateProperty>,
);
staticFieldInitializerAssignments = [];
staticFieldInitializerExpressions = [];
}

if (hasDecorators && version === "2023-11") {
Expand All @@ -1219,45 +1234,46 @@ function transformClass(
t.thisExpression(),
]);
if (!isStatic) {
fieldInitializerAssignments.push(initExtraCall);
fieldInitializerExpressions.push(initExtraCall);
} else {
staticFieldInitializerAssignments.push(initExtraCall);
staticFieldInitializerExpressions.push(initExtraCall);
}
}
}
}
}

if (fieldInitializerAssignments.length > 0) {
if (fieldInitializerExpressions.length > 0) {
const isDerivedClass = !!path.node.superClass;
if (constructorPath) {
if (isDerivedClass) {
insertExpressionsAfterSuperCallAndOptimize(
fieldInitializerAssignments,
fieldInitializerExpressions,
constructorPath,
protoInitLocal,
);
} else {
prependExpressionsToConstructor(
fieldInitializerAssignments,
fieldInitializerExpressions,
constructorPath,
);
}
} else {
path.node.body.body.unshift(
createConstructorFromExpressions(
fieldInitializerAssignments,
fieldInitializerExpressions,
isDerivedClass,
),
);
}
fieldInitializerAssignments = [];
fieldInitializerExpressions = [];
}

if (staticFieldInitializerAssignments.length > 0) {
if (staticFieldInitializerExpressions.length > 0) {
path.node.body.body.push(
createStaticBlockFromExpressions(staticFieldInitializerAssignments),
createStaticBlockFromExpressions(staticFieldInitializerExpressions),
);
staticFieldInitializerExpressions = [];
}

const elementDecorations = generateDecorationExprs(
Expand Down Expand Up @@ -1290,12 +1306,11 @@ function transformClass(
| t.ClassPrivateProperty
| t.ClassPrivateMethod
)[] = [];
let staticBlocks: t.StaticBlock[] = [];
path.get("body.body").forEach(element => {
// Static blocks cannot be compiled to "instance blocks", but we can inline
// them as IIFEs in the next property.
if (element.isStaticBlock()) {
staticBlocks.push(element.node);
staticFieldInitializerExpressions.push(staticBlockToIIFE(element.node));
element.remove();
return;
}
Expand All @@ -1307,11 +1322,12 @@ function transformClass(
(isProperty || element.isClassPrivateMethod()) &&
element.node.static
) {
if (isProperty && staticBlocks.length > 0) {
const allValues: t.Expression[] = staticBlocks.map(staticBlockToIIFE);
if (element.node.value) allValues.push(element.node.value);
element.node.value = maybeSequenceExpression(allValues);
staticBlocks = [];
if (isProperty && staticFieldInitializerExpressions.length > 0) {
prependExpressionsToFieldInitializer(
staticFieldInitializerExpressions,
element,
);
staticFieldInitializerExpressions = [];
}

element.node.static = false;
Expand All @@ -1320,7 +1336,7 @@ function transformClass(
}
});

if (statics.length > 0 || staticBlocks.length > 0) {
if (statics.length > 0 || staticFieldInitializerExpressions.length > 0) {
const staticsClass = template.expression.ast`
class extends ${state.addHelper("identity")} {}
` as t.ClassExpression;
Expand All @@ -1338,8 +1354,8 @@ function transformClass(

const newExpr = t.newExpression(staticsClass, []);

if (staticBlocks.length > 0) {
constructorBody.push(...staticBlocks.map(staticBlockToIIFE));
if (staticFieldInitializerExpressions.length > 0) {
constructorBody.push(...staticFieldInitializerExpressions);
}
if (classInitCall) {
classInitInjected = true;
Expand All @@ -1350,14 +1366,11 @@ function transformClass(
t.callExpression(t.super(), [t.cloneNode(classIdLocal)]),
);

// set isDerivedClass to false as we have already prepended super call
staticsClass.body.body.push(
t.classMethod(
"constructor",
t.identifier("constructor"),
[],
t.blockStatement([
t.expressionStatement(t.sequenceExpression(constructorBody)),
]),
createConstructorFromExpressions(
constructorBody,
/* isDerivedClass */ false,
),
);
} else {
Expand Down Expand Up @@ -1443,7 +1456,7 @@ function createLocalsAssignment(
elementDecorations: t.ArrayExpression | t.Identifier,
classDecorations: t.ArrayExpression | t.Identifier,
classDecorationsFlag: t.NumericLiteral,
maybePrivateBranName: t.PrivateName | null,
maybePrivateBrandName: t.PrivateName | null,
setClassName: t.Identifier | t.StringLiteral | undefined,
superClass: null | t.Expression,
state: PluginPass,
Expand All @@ -1463,56 +1476,55 @@ function createLocalsAssignment(
version === "2021-12" ||
(version === "2022-03" && !state.availableHelper("applyDecs2203R"))
) {
const lhs = t.arrayPattern([...elementLocals, ...classLocals]);
const rhs = t.callExpression(
lhs = t.arrayPattern([...elementLocals, ...classLocals]);
rhs = t.callExpression(
state.addHelper(version === "2021-12" ? "applyDecs" : "applyDecs2203"),
args,
);
return t.assignmentExpression("=", lhs, rhs);
} else if (version === "2022-03") {
rhs = t.callExpression(state.addHelper("applyDecs2203R"), args);
} else if (version === "2023-01") {
if (maybePrivateBrandName) {
args.push(createPrivateBrandCheckClosure(maybePrivateBrandName));
}
rhs = t.callExpression(state.addHelper("applyDecs2301"), args);
} else if (version === "2023-05") {
if (
maybePrivateBrandName ||
superClass ||
classDecorationsFlag.value !== 0
) {
args.push(classDecorationsFlag);
}
if (maybePrivateBrandName) {
args.push(createPrivateBrandCheckClosure(maybePrivateBrandName));
} else if (superClass) {
args.push(t.unaryExpression("void", t.numericLiteral(0)));
}
if (superClass) args.push(superClass);
rhs = t.callExpression(state.addHelper("applyDecs2305"), args);
}
}

if (
process.env.BABEL_8_BREAKING ||
version === "2023-11" ||
version === "2023-05"
) {
if (process.env.BABEL_8_BREAKING || version === "2023-11") {
if (
maybePrivateBranName ||
maybePrivateBrandName ||
superClass ||
classDecorationsFlag.value !== 0
) {
args.push(classDecorationsFlag);
}
if (maybePrivateBranName) {
args.push(
template.expression.ast`
_ => ${t.cloneNode(maybePrivateBranName)} in _
` as t.ArrowFunctionExpression,
);
if (maybePrivateBrandName) {
args.push(createPrivateBrandCheckClosure(maybePrivateBrandName));
} else if (superClass) {
args.push(t.unaryExpression("void", t.numericLiteral(0)));
}
if (superClass) args.push(superClass);
if (version === "2023-11") {
rhs = t.callExpression(state.addHelper("applyDecs2311"), args);
} else {
rhs = t.callExpression(state.addHelper("applyDecs2305"), args);
}
} else if (version === "2023-01") {
if (maybePrivateBranName) {
args.push(
template.expression.ast`
_ => ${t.cloneNode(maybePrivateBranName)} in _
` as t.ArrowFunctionExpression,
);
}
rhs = t.callExpression(state.addHelper("applyDecs2301"), args);
} else {
rhs = t.callExpression(state.addHelper("applyDecs2203R"), args);
rhs = t.callExpression(state.addHelper("applyDecs2311"), args);
}
// optimize `{ c: [classLocals] } = applyapplyDecs2203R(...)` to
// `[classLocals] = applyapplyDecs2203R(...).c`

// optimize `{ c: [classLocals] } = applyDecsHelper(...)` to
// `[classLocals] = applyDecsHelper(...).c`
if (elementLocals.length > 0) {
if (classLocals.length > 0) {
lhs = t.objectPattern([
Expand Down
@@ -1,4 +1,4 @@
let hasX, hasM, OriginalFoo;
let hasX, hasA, hasM, OriginalFoo;

class Bar {}

Expand All @@ -10,24 +10,32 @@ function dec(Foo) {
@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);