babel: [Bug]: Class Private Fields/Accessors/Methods must not be re-initialized on instance
š»
- Would you like to work on a fix?
How are you using Babel?
Programmatic API (babel.transform
, babel.parse
)
Input code
(See āPrevent private class members from being added more than onceā section in https://github.com/evanw/esbuild/releases/tag/v0.11.20#:~:text=Prevent private class members from being added more than once)
class Base {
constructor(obj) {
return obj;
}
}
let counter = 0;
class Derived extends Base {
#foo = ++counter;
static get(obj) {
return obj.#foo;
}
}
const foo = {};
new Derived(foo);
assert.equals(Derived.get(foo), 1);
// This should throw an error, private fields must not be re-initialized
// on an object that already contains the field.
assert.throws(() => {
new Derived(foo);
});
// ^ That should have thrown, but it doesn't.
// Must not re-initialize the field
assert.equals(Derived.get(foo), 1);
// But the counter is incremented (the initializer runs, but the field
// should not re-add)
assert.equals(counter, 2);
Configuration file name
babel.config.json
Configuration
{
"presets": [
[
"@babel/preset-env",
{
"shippedProposals": true,
"targets": {
"chrome": "75"
}
}
]
]
}
Current and expected behavior
Currently, this will re-initialize the field #foo
, but this is incorrect. It should throw an error when trying to initialize the field a second time.
Environment
- Babel version: v7.14.1
Possible solution
We should create new initializePrivateFieldSpec
, initializePrivateAccessorSpec
, and initializePrivateMethodSpec
(and helpers to initialize the field to a descriptor. Inside the helpers, we should check if the static
versions)WeakMap
/WeakSet
that represents the transformed field already contains the instance
key. If so, throw. Else, initialize.
Or, we could just have a simple checkPrivateFieldInitSpec
which does the check, but doesnāt initialize. Weād then call the check
before initializing a field.
After creating the helpers, we should call them in the appropriate place in https://github.com/babel/babel/blob/main/packages/babel-helper-create-class-features-plugin/src/fields.js (look for any function that ends in āInitSpecā).
Additional context
This is a medium difficulty issue, so could be tackled by someone with a little experience making changes to Babel.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 2
- Comments: 27 (22 by maintainers)
sure i can try it out
It looks good! The new function can be created in
packages/babel-helpers/src/helpers.js
, and it can be used using theaddHelper
internal method (you can Ctrl+F for it to see how it works).Uh, that link is auto-generated and unfortunately I think we donāt have docs for that internal package š
Thanks, I will start working right away
Yes @nicolo-ribaudo! Got a bit side-tracked in the past few weeks.
Could you implement the
initializePrivateFieldSpec
/initializePrivateMethodSpec
version? The helpers are defined at https://github.com/babel/babel/blob/main/packages/babel-helpers/src/helpers.js and used at https://github.com/babel/babel/blob/main/packages/babel-helper-create-class-features-plugin/src/fields.jsYes!
If it is the first time that you contribute to Babel, you can follow these steps: (you need to have
make
andyarn
available on your machine)git clone https://github.com/<YOUR_USERNAME>/babel.git && cd babel
yarn && make bootstrap
make watch
(ormake build
/yarn gulp build
whenever you change a file). When updating@babel/helpers
, Iām not 100% sure thatmake watch
works.exec.js
and/orinput.js
;output.js
will be automatically generated)yarn jest [name-of-the-package-to-test]
to run the testsoutput.js
files and run the tests againOVERWRITE=true yarn jest [name-of-the-package-to-test]
and they will be automatically updated.make test
to run all the testsgit push
and open a PR!could i help here?