-
-
Notifications
You must be signed in to change notification settings - Fork 255
Don't parse class properties without initializers when classProperties plugin is disabled, and Flow is enabled #300
Don't parse class properties without initializers when classProperties plugin is disabled, and Flow is enabled #300
Conversation
…s is disabled and Flow is enabled
@@ -771,8 +771,13 @@ pp.parseClassBody = function (node) { | |||
}; | |||
|
|||
pp.parseClassProperty = function (node) { | |||
const noPluginMsg = "You can only use Class Properties when the 'classProperties' plugin is enabled."; | |||
if (!node.typeAnnotation && !this.hasPlugin("classProperties")) { |
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 super happy about a flow-specific check leaking into the general parser, but I didn't see a straight-forward way to do this otherwise. Only other way I could see was to just have the flow extension for parseClassProperty
invoke this with an optional second param of hadType
, but even then, Flow-related stuff still leaks in.
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 code will not stay forever anyway, as as soon as class-properties are final, we can remove all 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.
We really need to do #178
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 code will not stay forever anyway, as as soon as class-properties are final, we can remove all this.
Good point
if (this.match(tt.eq)) { | ||
if (!this.hasPlugin("classProperties")) this.unexpected(); | ||
if (!this.hasPlugin("classProperties")) this.raise(this.state.start, noPluginMsg); |
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.
Pretty sure it's safe to provide a better message here. We should only get to this point if we're inside the top level of a class body and we've found either a =
or linebreak after an identifier.
if (this.match(tt.eq)) { | ||
if (!this.hasPlugin("classProperties")) this.unexpected(); | ||
if (!this.hasPlugin("classProperties")) this.raise(this.state.start, noPluginMsg); |
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 note I'm using this.state.start
rather than node.start
here, so we're pointing out the error where the =
is, rather than what could be the start of a type annotation in the scenario that the code being parsed is:
class Foo {
bar: string = 'bizz';
}
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 this was the same before, as this.unexpected()
uses this.state.start
Current coverage is 97.30% (diff: 100%)@@ master #300 diff @@
==========================================
Files 21 21
Lines 3993 4003 +10
Methods 478 480 +2
Messages 0 0
Branches 1178 1179 +1
==========================================
+ Hits 3892 3895 +3
- Misses 44 49 +5
- Partials 57 59 +2
|
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.
lgtm
This could be potentially breaking, for people relying on this wrong behaviour. Although I'm not sure if that'S a real case, as babel would not transform class properties when they are not active, but flow is and you use class properties in your code. I think babel throws in that case if I remember right.
Should we do it in 7? Thoughts?
@@ -771,8 +771,13 @@ pp.parseClassBody = function (node) { | |||
}; | |||
|
|||
pp.parseClassProperty = function (node) { | |||
const noPluginMsg = "You can only use Class Properties when the 'classProperties' plugin is enabled."; | |||
if (!node.typeAnnotation && !this.hasPlugin("classProperties")) { |
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 code will not stay forever anyway, as as soon as class-properties are final, we can remove all this.
if (this.match(tt.eq)) { | ||
if (!this.hasPlugin("classProperties")) this.unexpected(); | ||
if (!this.hasPlugin("classProperties")) this.raise(this.state.start, noPluginMsg); |
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 this was the same before, as this.unexpected()
uses this.state.start
@danez looks like this wouldn't affect most Babel users.
This seems like it'd only break things consuming the parser directly (like |
…s is disabled and Flow is enabled (#300)
I landed this in 7.0 now. |
Thanks @danez! |
On
master
, we'll currently parse the following, even withclassProperties
disabledThis was happening because we defer the check for the plugin until we're inside the body of
pp.parseClassProperty
, so thatFlow
can parse the following:Once inside of
pp.parseClassProperty
, we were only checking for the plugin if an initializer had been provided.We unfortunately can't just disallow Flow annotations for class properties when when
classProperties
are disabled, because Flow allows you to do:I marked this as a breaking change, but it's also technically a bug, so unsure if we want to defer to Babylon 7 or not.