Bug Report
Input Code
class A extends B {
#x;
method() {
super.#x;
}
}
repl
Expected behavior/code
It should throw a parser error.
Specification
In the class fields proposal, MemberExpression (which is the technical tern for "property access") is defined as follows:
MemberExpression:
PrimaryExpression
MemberExpression [ Expression ] <-- foo[bar]
MemberExpression . IdentifierName <-- foo.bar
MemberExpression TemplateLiteral <-- foo`bar`
SuperProperty
MetaProperty
new MemberExpression Arguments <-- new foo.bar()
MemberExpression . PrivateIdentifier <-- foo.#x
As you can see, .PrivateIdentifier (where a PrivateIdentifier is like #x) is only allowed after another MemberExpression.
Let's see what SuperProperty is. It is not redefined by the proposal, so we must search it in the main specification.
SuperProperty:
super [ Expression ] <-- super[foo]
super . IdentifierName <-- super.#x
As you might see, there is nothing allowing super.#x
Babel Configuration (.babelrc, package.json, cli command)
In order to test this bug, you must enable the classPrivateProperties parser plugin
Environment
Possible Solution
When we parse the super keyword, we check if it is followed by (, [ or . and throw otherwise:
|
if ( |
|
!this.match(tt.parenL) && |
|
!this.match(tt.bracketL) && |
|
!this.match(tt.dot) |
|
) { |
|
this.unexpected(); |
|
} |
|
|
|
return this.finishNode(node, "Super"); |
A naive solution would be to also check the next token, using this.lookahead(). However, in @babel/parser lookahead() is really expensive because it needs to clone the whole parser state, produce the next token and then reset the state to what it was before: it should be avoided when possible.
What we could do is to disallow it when we are parsing the MemberExpression rather than the super keyword:
|
} else if (this.eat(tt.dot)) { |
|
const node = this.startNodeAt(startPos, startLoc); |
|
node.object = base; |
|
node.property = this.parseMaybePrivateName(); |
|
node.computed = false; |
|
if (state.optionalChainMember) { |
|
node.optional = false; |
|
return this.finishNode(node, "OptionalMemberExpression"); |
|
} |
|
return this.finishNode(node, "MemberExpression"); |
After parsing the node.property (which is the "thing" after the dot), we can check if
- the base object is a
Super node, and
- the property is a
PrivateName node.
If both those condition are met, we should raise an error explaining that it is disallowed.
If you don't know how to clone Babel, follow these steps: (you need to have make and yarn available on your machine).
- 🔴 Write a comment there to let other possible contributors know that you are working on this bug.
- Fork the repo
- Run
git clone https://github.com/<YOUR_USERNAME>/babel.git && cd babel
- Run
yarn && make bootstrap
- Wait ⏳
- Run
make watch (or make build whenever you change a file)
- Add a test inside
packages/babel-parser/test/fixtures/experimental/class-private-properties. You can look in the folders to check how tests about errors are structured.
- Update the code!
yarn jest parser to run the tests
- If it is working, run
make test to run all the tests
- Run
git push and open a PR!
If you need any other help, you can join our Slack and ask in the #developement channel. *
*
I'm going bed now, but I'm sure you'll find someone else online! 🙂
Bug Report
Input Code
repl
Expected behavior/code
It should throw a parser error.
Specification
In the class fields proposal,
MemberExpression(which is the technical tern for "property access") is defined as follows:As you can see,
.PrivateIdentifier(where aPrivateIdentifieris like#x) is only allowed after anotherMemberExpression.Let's see what
SuperPropertyis. It is not redefined by the proposal, so we must search it in the main specification.As you might see, there is nothing allowing
super.#xBabel Configuration (.babelrc, package.json, cli command)
In order to test this bug, you must enable the
classPrivatePropertiesparser pluginEnvironment
Possible Solution
When we parse the
superkeyword, we check if it is followed by(,[or.and throw otherwise:babel/packages/babel-parser/src/parser/expression.js
Lines 912 to 920 in 9c1ad0a
A naive solution would be to also check the next token, using
this.lookahead(). However, in@babel/parserlookahead()is really expensive because it needs to clone the whole parser state, produce the next token and then reset the state to what it was before: it should be avoided when possible.What we could do is to disallow it when we are parsing the
MemberExpressionrather than thesuperkeyword:babel/packages/babel-parser/src/parser/expression.js
Lines 653 to 662 in 9c1ad0a
After parsing the
node.property(which is the "thing" after the dot), we can check ifSupernode, andPrivateNamenode.If both those condition are met, we should raise an error explaining that it is disallowed.
If you don't know how to clone Babel, follow these steps: (you need to have
makeandyarnavailable on your machine).git clone https://github.com/<YOUR_USERNAME>/babel.git && cd babelyarn && make bootstrapmake watch(ormake buildwhenever you change a file)packages/babel-parser/test/fixtures/experimental/class-private-properties. You can look in the folders to check how tests about errors are structured.yarn jest parserto run the testsmake testto run all the testsgit pushand open a PR!If you need any other help, you can join our Slack and ask in the
#developementchannel. **
I'm going bed now, but I'm sure you'll find someone else online! 🙂