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 decorator evaluation private environment #16325
Fix decorator evaluation private environment #16325
Conversation
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/56452 |
} | ||
|
||
expect([...A].map(fn => fn(B)).join(",")).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This edge case test is disabled because I can't figure out how to transform it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, can we introduce a new public element and delete it immediately after defined?
class C {
// for demo purpose, the `delete` expression can be directly inserted into staticInitializerAssignments
@(function(_, context) { context.addInitializer(function() { delete this._ } })
static [(/* decorator evaluations */, "_")];
}
Of course using delete
is a performance killer, but this approach will be only invoked when there is no public class elements, which should be quite rare. By doing so we can get rid of all function context variable replacement since the decorator expressions are guaranteed to be inserted within a computed key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this case is rare enough that:
- the perf hit is ok
- the perf it doesn't actually matter, because you are not going to access properties on instances of this class (because it, well... has no properties)
for delete
, let's put it in a static { delete this._ }
block at the beginning of the class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds good to me.
We can even do it when someone needs it. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for delete, let's put it in a static { delete this._ } block at the beginning of the class?
I plan to insert the delete expression right before the applyDecs
call, since its parent block is already the first class element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is now enabled and merged with decorator-evaluation-yield-private-super-property/exec.js
It also happens to catch a bug in the helper-replace-supers
, currently Babel is incorrectly replacing the super
in the decorators of the given class method. This should have been handled in the environmentVisitor
but the root class method path is not visited because the visitSelf
argument of traverse.node
is not exposed to the path.traverse
.
} | ||
|
||
B.m(); | ||
expect(receivedName).toBe("B"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test was renamed to "decorator-evaluation-this" and then augmented.
var _initStatic, _init_a, _init_a2, _get_a, _set_a, _init_computedKey, _init_computedKey2, _init_computedKey3, _init_computedKey4, _init_computedKey5, _init_computedKey6, _computedKey, _init_computedKey7, _Foo; | ||
let _computedKey; | ||
var _initStatic, _init_a, _init_a2, _get_a, _set_a, _init_computedKey, _init_computedKey2, _init_computedKey3, _init_computedKey4, _init_computedKey5, _init_computedKey6, _init_computedKey7, _Foo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we revert this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is intentional as it will fix an integration issue with the class properties transform. For context see https://github.com/babel/babel/pull/10029/files#r287785963
In this REPL example
function noop() {}
const classes = [];
for (let i = 0; i < 5; ++i) {
classes.push(
class A {
@noop
[i] = "my property";
}
);
}
var result = [];
for (const clazz of classes) {
result.push(Object.getOwnPropertyNames(new clazz())[0]);
}
console.log(result.join())
when we apply the decorators, static block and class properties plugin, it should print 0,1,2,3,4
but currently it prints 4,4,4,4,4
.
I can add a new test case for this issue.
If the output size is the concern, I can open a new PR to register all variable as the let
binding, as it will introduce much more test output changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please add a test!
Regarding to output size, we should first aim at correctness and then optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I didn't notice this was a bug fix, I thought the increased size didn't matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"I suggest review this PR by commits." ~ 13 commits 😛 |
const expressions = path.get("expressions"); | ||
return getComputedKeyCompletion(expressions[expressions.length - 1]); | ||
} | ||
return skipTransparentExprWrappers(path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this recourse if the result of skipTransparentExprWrappers
is a SequenceExpression
?
const key = fieldPath.get("key") as NodePath<t.Expression>; | ||
expressions.push(key.node); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If key
is already a sequence expression maybe we should do expression.push(...key.node.expressions)
?
Or -- this is probably so rare that it doesn't matter, but in this case could we have a test showing that we generated a "nested" sequence expression?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a key
is already a sequence expression, it could be generated by another Babel plugin. The intention here is try to reuse the uid memoiser, for example the computed keys transform can reuse the memoiser _computedKeys
generated by the decorator transform:
class C {
[decs = f(), _computedKey = g(), another_decs = h(), _computedKey];
}
but at this point there is no class features running before decorators, so there aren't much practical examples. I will add a test case for nested sequence expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
); | ||
} | ||
} else { | ||
// If the computed key is an uid reference, treat it as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why if we get to this else
branch the key is an uid reference?
EDIT: Oh I see -- could you rename memoiseComputedKey
to memoiseComputedKeyIfNotUid
, or add a comment before the call saying that it returns undefined
if and only if it's a uid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (isUidReference) { | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Move this early return to before const isMemoiseAssignment
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
|
||
expect([...A].map(fn => fn(B)).join(",")).toBe("B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X,B#X"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this case is rare enough that:
- the perf hit is ok
- the perf it doesn't actually matter, because you are not going to access properties on instances of this class (because it, well... has no properties)
for delete
, let's put it in a static { delete this._ }
block at the beginning of the class?
|
||
const computedKeysPath = applyDecoratorWrapperPath.get("body")[0]; | ||
|
||
// Capture lexical this and super call, replace their usage in computed key assignments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would
function hoistFunctionEnvironment( |
Or maybe we could even "polyfill" it for Babel 7, doing terrible stuff:
function hoistFunctionEnvironment(path) {
Object.defineProperty(path, "isArrowFunctionExpression", {
get() {
delete path.isArrowFunctionExpression;
return () => true;
}
});
return path.unwrapFunctionEnvironment();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! I didn't realize we have such a utility in the traverse library. However I am down to the temporary property approach and hopefully we can remove all the lexical variables capturing logic here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -1659,6 +1672,32 @@ function transformClass( | |||
} | |||
|
|||
originalClass.body.body.unshift(t.staticBlock([])); | |||
if (computedKeyAssignments.length > 0) { | |||
// todo: the following branch will fail on 2023-05 version | |||
if (version === "2023-11") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
process.env.BABEL_8_BREAKING || version === "2023-11"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is eventually removed in bdee20d.
static m() { | ||
@noop | ||
class C { | ||
@(receivedName = super.name, noop) p; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test with a decorator that references both super
and a private field in the same decorator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this test look good?
Lines 12 to 29 in 0b8f0bc
class A extends CaptureFactory { | |
static #X = "A#X"; | |
static *[Symbol.iterator] () { | |
B = class B { | |
static #X = "B#X"; | |
@(yield* super.id(_ => _.#X), dummy) method () {} | |
@(yield* super.id(_ => _.#X), dummy) static method () {} | |
@(yield* super.id(_ => _.#X), dummy) get getter () {} | |
@(yield* super.id(_ => _.#X), dummy) static get getter () {} | |
@(yield* super.id(_ => _.#X), dummy) set setter (v) {} | |
@(yield* super.id(_ => _.#X), dummy) static set setter (v) {} | |
@(yield* super.id(_ => _.#X), dummy) property; | |
@(yield* super.id(_ => _.#X), dummy) static property; | |
@(yield* super.id(_ => _.#X), dummy) accessor accessor; | |
@(yield* super.id(_ => _.#X), dummy) static accessor accessor; | |
} | |
} | |
} |
Edit: I can add a super-call
flavor if you mean super()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is ok, I somehow missed it.
This change ensures that 1) non static computed key will share the same function context when moved into the non-static class 2) evaluations of decorators and computed keys will always precede static computed keys, given that they have been moved into computed key assignments before
so that we can still preserve the production params [yield], [await] inherited from the outer scope
test262 seems to be relevant, while the other CI failures are not. Considering that this PR rebase may be complicated, we can postpone the #16326 merge. |
0b8f0bc
to
d837c27
Compare
static { | ||
_xDecs = dec; | ||
delete this._; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New PR idea: We can optimize them, potentially reusing the usesFnContext
diagnostic info of each decorators sequence.
0b8809e
to
d33d87b
Compare
|
||
// Recrawl the scope to make sure new identifiers are properly synced | ||
path.scope.crawl(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This branch is removed because the computed key in a vanilla class accessor is now memoised in place.
I am investigating the test262 error. |
try { | ||
t.traverseFast(expression, node => { | ||
if ( | ||
t.isThisExpression(node) || | ||
t.isSuper(node) || | ||
t.isYieldExpression(node) || | ||
t.isAwaitExpression(node) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function determines whether the class / element decorator evaluations should be moved into the applyDecs
static block. If the decorator expression contains await
or yield
, we should not move it since the static block can not provide correct function context.
const dec = () => {}; | ||
let _Class; | ||
new class extends babelHelpers.identity { | ||
static { | ||
class Class { | ||
static { | ||
({ | ||
e: [_init_m, _call_o, _call_p, _call_q, _init_r, _get_r, _set_r, _init_d, _call_f, _call_g, _call_g2, _init_h, _get_h, _set_h, _init_i, _init_n, _init_a, _init_e, _initProto, _initStatic], | ||
c: [_Class, _initClass] | ||
} = babelHelpers.applyDecs2301(this, [[dec, 7, "j"], [dec, 8, "k"], [dec, 9, "l"], [dec, 6, "m"], [dec, 7, "o", function () {}], [dec, 8, "p", function () {}], [dec, 9, "q", function (v) {}], [dec, 6, "r", o => o.#D, (o, v) => o.#D = v], [dec, 2, "b"], [dec, 3, "c"], [dec, 4, "c"], [dec, 1, "d"], [dec, 2, "f", function () {}], [dec, 3, "g", function () {}], [dec, 4, "g", function (v) {}], [dec, 1, "h", o => o.#B, (o, v) => o.#B = v], [dec, 5, "i"], [dec, 5, "n", o => o.#n, (o, v) => o.#n = v], [dec, 0, "a"], [dec, 0, "e", o => o.#e, (o, v) => o.#e = v]], [dec], _ => #e in _)); | ||
_initStatic(this); | ||
} | ||
#f = _call_f; | ||
a = (_initProto(this), _init_a(this)); | ||
b() {} | ||
get c() {} | ||
set c(v) {} | ||
#A = _init_d(this); | ||
get d() { | ||
return this.#A; | ||
} | ||
set d(v) { | ||
this.#A = v; | ||
} | ||
#e = _init_e(this); | ||
get #g() { | ||
return _call_g(this); | ||
} | ||
set #g(v) { | ||
_call_g2(this, v); | ||
} | ||
#B = _init_h(this); | ||
set #h(v) { | ||
_set_h(this, v); | ||
} | ||
get #h() { | ||
return _get_h(this); | ||
} | ||
static j() {} | ||
static get k() {} | ||
static set l(v) {} | ||
static get m() { | ||
return this.#C; | ||
} | ||
static set m(v) { | ||
this.#C = v; | ||
} | ||
static [class Class { | ||
static { | ||
({ | ||
e: [_init_m, _call_o, _call_p, _call_q, _init_r, _get_r, _set_r, _init_d, _call_f, _call_g, _call_g2, _init_h, _get_h, _set_h, _init_i, _init_n, _init_a, _init_e, _initProto, _initStatic], | ||
c: [_Class, _initClass] | ||
} = babelHelpers.applyDecs2301(this, [[dec, 7, "j"], [dec, 8, "k"], [dec, 9, "l"], [dec, 6, "m"], [dec, 7, "o", function () {}], [dec, 8, "p", function () {}], [dec, 9, "q", function (v) {}], [dec, 6, "r", o => o.#D, (o, v) => o.#D = v], [dec, 2, "b"], [dec, 3, "c"], [dec, 4, "c"], [dec, 1, "d"], [dec, 2, "f", function () {}], [dec, 3, "g", function () {}], [dec, 4, "g", function (v) {}], [dec, 1, "h", o => o.#B, (o, v) => o.#B = v], [dec, 5, "i"], [dec, 5, "n", o => o.#n, (o, v) => o.#n = v], [dec, 0, "a"], [dec, 0, "e", o => o.#e, (o, v) => o.#e = v]], [dec], _ => #e in _)); | ||
_initStatic(this); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can optimize this output in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. Though the output here is only one trailing ;
more than what we currently have. The output change here is introduced in 2d34eeb, which changes the output static { class { ... } }
to static [ class { ... } ];
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we can merge them into one class. :)
The changes here look good to me, the properties are kept in the outer class which greatly improves readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge them into one class
The non static elements are split because the static fields have to be installed on the replaced class. If we can merge them without too much effort, #16176 will be automatically resolved.
path.stop(); | ||
} | ||
}, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can directly access the originalClass
path according to the AST hierarchy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return getComputedKeyCompletion(expressions[expressions.length - 1]); | ||
} | ||
return path; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this function is not meant for complex completion cases like path.getCompletionRecord()
can handle, e.g. it does not support do expressions, I suggest rename it to getComputedKeyLastElement
so that it is not confused with the completion concept in the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const applyDecsBody = applyDecoratorWrapper.body; | ||
if (computedKeyAssignments.length > 0) { | ||
const elements = originalClassPath.get("body.body"); | ||
let lastPublicElement: NodePath<t.ClassProperty | t.ClassMethod>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The computedKeyAssignments
hosts decorator and computed keys evaluation results. They will be referenced in the applyDecs
call emited in the first static block of the class. I think the output will be slightly more readable if we insert the assignments to the first public element, so that they will not be too far away from where they will be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- rename some routines - improve originalClassPath access, to avoid a full traversal - add more jsdoc coments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done!
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [@babel/traverse](https://babel.dev/docs/en/next/babel-traverse) ([source](https://github.com/babel/babel)) | resolutions | minor | [`7.23.9` -> `7.24.1`](https://renovatebot.com/diffs/npm/@babel%2ftraverse/7.23.9/7.24.1) | --- ### Release Notes <details> <summary>babel/babel (@​babel/traverse)</summary> ### [`v7.24.1`](https://github.com/babel/babel/blob/HEAD/CHANGELOG.md#v7241-2024-03-19) [Compare Source](babel/babel@v7.24.0...v7.24.1) ##### 🐛 Bug Fix - `babel-helper-create-class-features-plugin`, `babel-plugin-proposal-decorators` - [#​16350](babel/babel#16350) Fix decorated class computed keys ordering ([@​JLHwung](https://github.com/JLHwung)) - [#​16344](babel/babel#16344) Fix decorated class static field private access ([@​JLHwung](https://github.com/JLHwung)) - `babel-plugin-proposal-decorators`, `babel-plugin-proposal-json-modules`, `babel-plugin-transform-async-generator-functions`, `babel-plugin-transform-regenerator`, `babel-plugin-transform-runtime`, `babel-preset-env` - [#​16329](babel/babel#16329) Respect `moduleName` for `@babel/runtime/regenerator` imports ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-helper-create-class-features-plugin`, `babel-plugin-proposal-decorators`, `babel-plugin-proposal-pipeline-operator`, `babel-plugin-transform-class-properties` - [#​16331](babel/babel#16331) Fix decorator memoiser binding kind ([@​JLHwung](https://github.com/JLHwung)) - `babel-helper-create-class-features-plugin`, `babel-helper-replace-supers`, `babel-plugin-proposal-decorators`, `babel-plugin-transform-class-properties` - [#​16325](babel/babel#16325) Fix decorator evaluation private environment ([@​JLHwung](https://github.com/JLHwung)) ##### 📝 Documentation - [#​16319](babel/babel#16319) Update SECURITY.md ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) ##### 🏠 Internal - `babel-code-frame`, `babel-highlight` - [#​16359](babel/babel#16359) Replace `chalk` with `picocolors` ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-helper-fixtures`, `babel-helpers`, `babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression`, `babel-plugin-proposal-pipeline-operator`, `babel-plugin-transform-unicode-sets-regex`, `babel-preset-env`, `babel-preset-flow` - [#​16352](babel/babel#16352) Run Babel transform tests on old node if possible ([@​JLHwung](https://github.com/JLHwung)) - `babel-helpers`, `babel-plugin-transform-async-generator-functions`, `babel-plugin-transform-class-properties`, `babel-plugin-transform-class-static-block`, `babel-plugin-transform-modules-commonjs`, `babel-plugin-transform-modules-systemjs`, `babel-plugin-transform-regenerator`, `babel-plugin-transform-runtime`, `babel-preset-env`, `babel-runtime-corejs3`, `babel-runtime`, `babel-standalone` - [#​16323](babel/babel#16323) Allow separate helpers to be excluded in Babel 8 ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-helper-module-imports`, `babel-plugin-proposal-import-wasm-source`, `babel-plugin-proposal-json-modules`, `babel-plugin-proposal-record-and-tuple`, `babel-plugin-transform-react-jsx-development`, `babel-plugin-transform-react-jsx` - [#​16349](babel/babel#16349) Support merging imports in import injector ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-helper-create-class-features-plugin`, `babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression`, `babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining`, `babel-plugin-bugfix-v8-static-class-fields-redefine-readonly`, `babel-plugin-external-helpers`, `babel-plugin-proposal-async-do-expressions`, `babel-plugin-proposal-decorators`, `babel-plugin-proposal-destructuring-private`, `babel-plugin-proposal-do-expressions`, `babel-plugin-proposal-duplicate-named-capturing-groups-regex`, `babel-plugin-proposal-explicit-resource-management`, `babel-plugin-proposal-export-default-from`, `babel-plugin-proposal-function-bind`, `babel-plugin-proposal-function-sent`, `babel-plugin-proposal-import-attributes-to-assertions`, `babel-plugin-proposal-import-defer`, `babel-plugin-proposal-import-wasm-source`, `babel-plugin-proposal-json-modules`, `babel-plugin-proposal-optional-chaining-assign`, `babel-plugin-proposal-partial-application`, `babel-plugin-proposal-pipeline-operator`, `babel-plugin-proposal-record-and-tuple`, `babel-plugin-proposal-regexp-modifiers`, `babel-plugin-proposal-throw-expressions`, `babel-plugin-syntax-async-do-expressions`, `babel-plugin-syntax-decimal`, `babel-plugin-syntax-decorators`, `babel-plugin-syntax-destructuring-private`, `babel-plugin-syntax-do-expressions`, `babel-plugin-syntax-explicit-resource-management`, `babel-plugin-syntax-export-default-from`, `babel-plugin-syntax-flow`, `babel-plugin-syntax-function-bind`, `babel-plugin-syntax-function-sent`, `babel-plugin-syntax-import-assertions`, `babel-plugin-syntax-import-attributes`, `babel-plugin-syntax-import-defer`, `babel-plugin-syntax-import-reflection`, `babel-plugin-syntax-import-source`, `babel-plugin-syntax-jsx`, `babel-plugin-syntax-module-blocks`, `babel-plugin-syntax-optional-chaining-assign`, `babel-plugin-syntax-partial-application`, `babel-plugin-syntax-pipeline-operator`, `babel-plugin-syntax-record-and-tuple`, `babel-plugin-syntax-throw-expressions`, `babel-plugin-syntax-typescript`, `babel-plugin-transform-arrow-functions`, `babel-plugin-transform-async-generator-functions`, `babel-plugin-transform-async-to-generator`, `babel-plugin-transform-block-scoped-functions`, `babel-plugin-transform-block-scoping`, `babel-plugin-transform-class-properties`, `babel-plugin-transform-class-static-block`, `babel-plugin-transform-classes`, `babel-plugin-transform-computed-properties`, `babel-plugin-transform-destructuring`, `babel-plugin-transform-dotall-regex`, `babel-plugin-transform-duplicate-keys`, `babel-plugin-transform-dynamic-import`, `babel-plugin-transform-exponentiation-operator`, `babel-plugin-transform-export-namespace-from`, `babel-plugin-transform-flow-comments`, `babel-plugin-transform-flow-strip-types`, `babel-plugin-transform-for-of`, `babel-plugin-transform-function-name`, `babel-plugin-transform-instanceof`, `babel-plugin-transform-jscript`, `babel-plugin-transform-json-strings`, `babel-plugin-transform-literals`, `babel-plugin-transform-logical-assignment-operators`, `babel-plugin-transform-member-expression-literals`, `babel-plugin-transform-modules-amd`, `babel-plugin-transform-modules-commonjs`, `babel-plugin-transform-modules-systemjs`, `babel-plugin-transform-modules-umd`, `babel-plugin-transform-new-target`, `babel-plugin-transform-nullish-coalescing-operator`, `babel-plugin-transform-numeric-separator`, `babel-plugin-transform-object-assign`, `babel-plugin-transform-object-rest-spread`, `babel-plugin-transform-object-set-prototype-of-to-assign`, `babel-plugin-transform-object-super`, `babel-plugin-transform-optional-catch-binding`, `babel-plugin-transform-optional-chaining`, `babel-plugin-transform-parameters`, `babel-plugin-transform-private-methods`, `babel-plugin-transform-private-property-in-object`, `babel-plugin-transform-property-literals`, `babel-plugin-transform-property-mutators`, `babel-plugin-transform-proto-to-assign`, `babel-plugin-transform-react-constant-elements`, `babel-plugin-transform-react-display-name`, `babel-plugin-transform-react-inline-elements`, `babel-plugin-transform-react-jsx-compat`, `babel-plugin-transform-react-jsx-self`, `babel-plugin-transform-react-jsx-source`, `babel-plugin-transform-react-pure-annotations`, `babel-plugin-transform-regenerator`, `babel-plugin-transform-reserved-words`, `babel-plugin-transform-runtime`, `babel-plugin-transform-shorthand-properties`, `babel-plugin-transform-spread`, `babel-plugin-transform-sticky-regex`, `babel-plugin-transform-strict-mode`, `babel-plugin-transform-template-literals`, `babel-plugin-transform-typeof-symbol`, `babel-plugin-transform-typescript`, `babel-plugin-transform-unicode-escapes`, `babel-plugin-transform-unicode-property-regex`, `babel-plugin-transform-unicode-regex`, `babel-plugin-transform-unicode-sets-regex`, `babel-preset-env`, `babel-preset-flow`, `babel-preset-react`, `babel-preset-typescript` - [#​16332](babel/babel#16332) Test Babel 7 plugins compatibility with Babel 8 core ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-compat-data`, `babel-plugin-transform-object-rest-spread`, `babel-preset-env` - [#​16318](babel/babel#16318) \[babel 8] Fix `@babel/compat-data` package.json ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) ##### 🔬 Output optimization - `babel-helper-replace-supers`, `babel-plugin-transform-class-properties`, `babel-plugin-transform-classes`, `babel-plugin-transform-parameters`, `babel-plugin-transform-runtime` - [#​16345](babel/babel#16345) Optimize the use of `assertThisInitialized` after `super()` ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-plugin-transform-class-properties`, `babel-plugin-transform-classes` - [#​16343](babel/babel#16343) Use simpler `assertThisInitialized` more often ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-plugin-proposal-decorators`, `babel-plugin-transform-class-properties`, `babel-plugin-transform-object-rest-spread`, `babel-traverse` - [#​16342](babel/babel#16342) Consider well-known and registered symbols as literals ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-core`, `babel-plugin-external-helpers`, `babel-plugin-proposal-decorators`, `babel-plugin-proposal-function-bind`, `babel-plugin-transform-class-properties`, `babel-plugin-transform-classes`, `babel-plugin-transform-flow-comments`, `babel-plugin-transform-flow-strip-types`, `babel-plugin-transform-function-name`, `babel-plugin-transform-modules-systemjs`, `babel-plugin-transform-parameters`, `babel-plugin-transform-private-property-in-object`, `babel-plugin-transform-react-jsx`, `babel-plugin-transform-runtime`, `babel-plugin-transform-spread`, `babel-plugin-transform-typescript`, `babel-preset-env` - [#​16326](babel/babel#16326) Reduce the use of class names ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) ### [`v7.24.0`](https://github.com/babel/babel/blob/HEAD/CHANGELOG.md#v7240-2024-02-28) [Compare Source](babel/babel@v7.23.9...v7.24.0) ##### 🚀 New Feature - `babel-standalone` - [#​11696](babel/babel#11696) Export babel tooling packages in `@babel/standalone` ([@​ajihyf](https://github.com/ajihyf)) - `babel-core`, `babel-helper-create-class-features-plugin`, `babel-helpers`, `babel-plugin-transform-class-properties` - [#​16267](babel/babel#16267) Implement `noUninitializedPrivateFieldAccess` assumption ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-helper-create-class-features-plugin`, `babel-helpers`, `babel-plugin-proposal-decorators`, `babel-plugin-proposal-pipeline-operator`, `babel-plugin-syntax-decorators`, `babel-plugin-transform-class-properties`, `babel-runtime-corejs2`, `babel-runtime-corejs3`, `babel-runtime` - [#​16242](babel/babel#16242) Support decorator 2023-11 normative updates ([@​JLHwung](https://github.com/JLHwung)) - `babel-preset-flow` - [#​16309](babel/babel#16309) \[babel 7] Allow setting `ignoreExtensions` in Flow preset ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - [#​16284](babel/babel#16284) Add `experimental_useHermesParser` option in `preset-flow` ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-helper-import-to-platform-api`, `babel-plugin-proposal-import-wasm-source`, `babel-plugin-proposal-json-modules`, `babel-standalone` - [#​16172](babel/babel#16172) Add transform support for JSON modules imports ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-plugin-transform-runtime` - [#​16241](babel/babel#16241) Add back `moduleName` option to `@babel/plugin-transform-runtime` ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-parser`, `babel-types` - [#​16277](babel/babel#16277) Allow import attributes for `TSImportType` ([@​sosukesuzuki](https://github.com/sosukesuzuki)) ##### 🐛 Bug Fix - `babel-plugin-proposal-do-expressions`, `babel-traverse` - [#​16305](babel/babel#16305) fix: avoid `popContext` on unvisited node paths ([@​JLHwung](https://github.com/JLHwung)) - `babel-helper-create-class-features-plugin`, `babel-plugin-transform-private-methods`, `babel-plugin-transform-private-property-in-object` - [#​16312](babel/babel#16312) Fix class private properties when `privateFieldsAsSymbols` ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-helper-create-class-features-plugin`, `babel-plugin-transform-private-methods` - [#​16307](babel/babel#16307) Fix the support of `arguments` in private `get/set` method ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-helper-create-class-features-plugin`, `babel-helpers`, `babel-plugin-proposal-decorators` - [#​16287](babel/babel#16287) Reduce decorator static property size ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-helper-create-class-features-plugin`, `babel-plugin-proposal-decorators` - [#​16281](babel/babel#16281) Fix evaluation order of decorators with cached receiver ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - [#​16279](babel/babel#16279) Fix decorator this memoization ([@​JLHwung](https://github.com/JLHwung)) - [#​16266](babel/babel#16266) Preserve `static` on decorated private `accessor` ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - [#​16258](babel/babel#16258) fix: handle decorated async private method and generator ([@​JLHwung](https://github.com/JLHwung)) - `babel-helper-create-class-features-plugin`, `babel-plugin-proposal-decorators`, `babel-plugin-transform-async-generator-functions`, `babel-plugin-transform-private-methods`, `babel-plugin-transform-private-property-in-object`, `babel-plugin-transform-typescript`, `babel-preset-env` - [#​16275](babel/babel#16275) Fix class private properties when `privateFieldsAsProperties` ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-helpers` - [#​16268](babel/babel#16268) Do not consider `arguments` in a helper as a global reference ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-helpers`, `babel-plugin-proposal-decorators` - [#​16270](babel/babel#16270) Handle symbol key class elements decoration ([@​JLHwung](https://github.com/JLHwung)) - [#​16265](babel/babel#16265) Do not define `access.get` for public setter decorators ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) ##### 💅 Polish - `babel-core`, `babel-helper-create-class-features-plugin`, `babel-preset-env` - [#​12428](babel/babel#12428) Suggest using `BABEL_SHOW_CONFIG_FOR` for config problems ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) ##### 🏠 Internal - `babel-helper-transform-fixture-test-runner` - [#​16278](babel/babel#16278) Continue writing `output.js` when `exec.js` throws ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) ##### 🔬 Output optimization - `babel-helper-create-class-features-plugin`, `babel-plugin-proposal-decorators` - [#​16306](babel/babel#16306) Avoid intermediate functions for private accessors with decs ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-helper-create-class-features-plugin`, `babel-helpers`, `babel-plugin-proposal-decorators`, `babel-plugin-proposal-pipeline-operator`, `babel-plugin-transform-class-properties` - [#​16294](babel/babel#16294) More aggressively inline decorators in the static block ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-helper-create-class-features-plugin`, `babel-helpers`, `babel-plugin-transform-private-methods` - [#​16283](babel/babel#16283) Do not use `classPrivateMethodGet` ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-helper-create-class-features-plugin`, `babel-helpers`, `babel-plugin-proposal-decorators` - [#​16287](babel/babel#16287) Reduce decorator static property size ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) - `babel-helper-create-class-features-plugin`, `babel-plugin-proposal-decorators`, `babel-plugin-transform-class-properties` - [#​16280](babel/babel#16280) Reduce element decorator temp variables ([@​JLHwung](https://github.com/JLHwung)) - `babel-helper-create-class-features-plugin`, `babel-helper-fixtures`, `babel-helpers`, `babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining`, `babel-plugin-proposal-decorators`, `babel-plugin-proposal-destructuring-private`, `babel-plugin-proposal-optional-chaining-assign`, `babel-plugin-transform-class-properties`, `babel-plugin-transform-class-static-block`, `babel-plugin-transform-private-methods`, `babel-plugin-transform-private-property-in-object`, `babel-preset-env`, `babel-runtime-corejs2`, `babel-runtime-corejs3`, `babel-runtime` - [#​16261](babel/babel#16261) Do not use descriptors for private class elements ([@​nicolo-ribaudo](https://github.com/nicolo-ribaudo)) - `babel-helpers`, `babel-plugin-proposal-decorators` - [#​16263](babel/babel#16263) Reduce helper size for decorator 2023-11 ([@​liuxingbaoyu](https://github.com/liuxingbaoyu)) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4wLjAiLCJ1cGRhdGVkSW5WZXIiOiIzNy4wLjAiLCJ0YXJnZXRCcmFuY2giOiJkZXZlbG9wIn0=--> Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/random-bunny/pulls/156 Co-authored-by: Renovate Bot <renovate@vylpes.com> Co-committed-by: Renovate Bot <renovate@vylpes.com>
In this PR we move the element decorator evaluation from the preface of class declaration into computed key.
Previously they are evaluated outside the class, immediate after class decorator evaluations. However, because the element decorators are defined within the class syntax, they should have access to the private variables defined in the current class.
The current evaluation storage:
If a class has only private elements and static blocks, we will insert the decorator evaluations before theapplyDecs
call. We will replace all function context usage before moving them into the static block. However, this is still not safe because decorators expressions / computed keys inherit the outer level[Yield]
and[Await]
production parameter, while the static block where we insertapplyDecs
call can not be a generator / async function. Given that the scenaraio of private-only class is rare, I would like to trade it with this general private fix.I suggest review this PR by commits.