-
-
Notifications
You must be signed in to change notification settings - Fork 256
Conversation
…fined this will return undefined. If the object on which you want to access the property is defined, the value of the propery will be given back.
…ess. (.? or ?.[) If the object is undefined this will return undefined. If the object on which you want to access the property is defined, the value of the propery will be given back.
…at-optional-chaining
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.
Looks OK to me, but it already has merge conflicts 😕
AST change is adding an optional
boolean to MemberExpression
ast/spec.md
Outdated
} | ||
``` | ||
|
||
A member expression. If `computed` is `true`, the node corresponds to a computed (`a[b]`) member expression and `property` is an `Expression`. If `computed` is `false`, the node corresponds to a static (`a.b`) member expression and `property` is an `Identifier`. | ||
A member expression. If `computed` is `true`, the node corresponds to a computed (`a[b]`) member expression and `property` is an `Expression`. If `computed` is `false`, the node corresponds to a static (`a.b`) member expression and `property` is an `Identifier`. The `optional` flags indecates that the member expression can be called even if the object is null or undefined. If this is the object value (null/undefined) should be returned. |
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.
indicates
src/tokenizer/index.js
Outdated
@@ -391,6 +391,18 @@ export default class Tokenizer { | |||
return this.finishOp(code === 61 ? tt.eq : tt.prefix, 1); | |||
} | |||
|
|||
readToken_question() { // '?' | |||
const next = this.input.charCodeAt(this.state.pos + 1); | |||
if (next === 46) { // 46 = question '.' |
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.
Comment is confusing; just 46 = '.'
should work.
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.
Or just // '.'
like the other parts of the code
src/parser/expression.js
Outdated
@@ -301,6 +301,24 @@ export default class ExpressionParser extends LValParser { | |||
node.object = base; | |||
node.callee = this.parseNoCallExpr(); | |||
return this.parseSubscripts(this.finishNode(node, "BindExpression"), startPos, startLoc, noCalls); | |||
|
|||
} else if (this.eat(tt.questionDot)) { |
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.
Similar to the other PR, we need to add a flag. I added the steps in https://github.com/babel/babylon/blob/master/CONTRIBUTING.md#creating-a-new-plugin-spec-new.
hasPlugin('nullPropagation')
or hasPlugin('optionalChaining')
, etc. Probably optionalChaining
since the repo was changed to that.
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 added the plugin check, updated the corresponding documentation and also added an explicit error message since it's a new syntax.
@@ -0,0 +1 @@ | |||
func?.() |
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 doesn't have an expected?
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.
Doesn't parse yet, need to be implemented (i'm still WIP)
@@ -0,0 +1 @@ | |||
new C?.() |
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 doesn't have an expected?
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.
Doesn't parse yet, need to be implemented (i'm still WIP)
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.
Nice work!
- add
hasPlugin
checks where necessary - add 2 missing expected checks (Optional Chaining Operator estree/estree#146, what do we do with new and function calls?)
- Can we have some more tests? Like at least one to show that you can have
a?.b?.c
(multiple chaining in one member expression - Also that
foo ? .3 : 0
is parsed as ternary and not optional chaining even while thehasPlugin
check is true - Are there other early errors/tests? Like what if you try to do
a.b?.c
ora?.b.c.?.d
, etc
cc @gisenberg for review, also @kristofdegrave, @rattrayalex
When I experimented with this about three years ago, I also went the route to make MemberExpressions optional. Seems like that's the way to go! :) |
I believe this breaks valid syntax. The expression |
@kerhong Yep, I mentioned this in my review and it's also in https://github.com/tc39/proposal-optional-chaining#notes. |
src/parser/expression.js
Outdated
base.name === "async" && | ||
!this.canInsertSemicolon(); | ||
|
||
node.arguments = this.parseCallExpressionArguments(tt.parenR, possibleAsync); |
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.
There's no callee
Codecov Report
@@ Coverage Diff @@
## master #545 +/- ##
==========================================
- Coverage 98.14% 98.14% -0.01%
==========================================
Files 22 22
Lines 3620 3663 +43
Branches 1012 1023 +11
==========================================
+ Hits 3553 3595 +42
- Misses 24 25 +1
Partials 43 43
Continue to review full report at Codecov.
|
Opened a PR to complete the work, so hopefully this'll land soon. Does anyone know why |
Finish optionalChaining plugin
Thanks for the PR @jridgewell, that's a nice job.
Maybe because of the syntax? |
cc @yungsters @zertosh if you want to review. Will check again tomorrow |
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.
Looks good to me, great work! Thanks for your contribution!
this.next(); | ||
|
||
const node = this.startNodeAt(startPos, startLoc); | ||
|
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.
Could probably just move node.optional = true;
to here since it's in all the if conditionals?
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 was trying to keep the property ordering consistent between optional and non-optional branches. See the #parseNew
as well.
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.
Seems legit; I think the transform is where I'll have more opinions than the parsing :-)
readToken_question() { // '?' | ||
const next = this.input.charCodeAt(this.state.pos + 1); | ||
const next2 = this.input.charCodeAt(this.state.pos + 2); | ||
if (next === 46 && !(next2 >= 48 && next2 <= 57)) { // '.' not followed by a number |
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.
what are these magic numbers? could these be stored in named variables, so it's clear what "46" means?
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.
These are char codes. I'll add some contants to improve readability, thanks.
🎉 🎉 |
Nice work everyone! Really appreciating the reviews! Babel transform PR is |
Actually, the transform PR is babel/babel#5813. |
Based on the spec here.
AST change:
Edit:
TODO
a?.b.c.?.d
? (skipping ?. in between)