Reimplement parser comment attachment to avoid duplicates and generally improve it#9084
Reimplement parser comment attachment to avoid duplicates and generally improve it#9084loganfsmyth wants to merge 4 commits intobabel:masterfrom
Conversation
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/9461/ |
1 similar comment
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/9461/ |
|
I will have a look at it soon. I know we had problems with changing locations of comments in the past and I experienced them in react-docgen so I will plug this PR into there and see what fails and if i can make the jsdoc parsing work correctly or it just happens to work. We can also try to run prettier with this change and see if their tests work. |
|
Ok I plugged it into prettier and one test failed, but the recorded snapshots looks incorrect. The changed comment behavior in this PR seems to fix it 👍: input: const Component = branch/*:: <Props, ExternalProps> */(
({ src }) => !src,
// $FlowFixMe
renderNothing,
)(BaseComponent);
const C = b/*:: <A> */(foo) + c/*:: <B> */(bar);
foo/*::<bar>*/(baz);
foo/*::<bar>*/();output diff: - Expected
+ Received
const Component = branch/*:: <Props, ExternalProps> */(
- /*:: <Props, ExternalProps> */ ({ src }) => !src,
+ ({ src }) => !src,
// $FlowFixMe
renderNothing
)(BaseComponent);
- const C = b/*:: <A> */(/*:: <A> */ foo) + c/*:: <B> */(/*:: <B> */ bar);
+ const C = b/*:: <A> */(foo) + c/*:: <B> */(bar);
- foo/*:: <bar> */(/*::<bar>*/ baz);
+ foo/*:: <bar> */(baz);
foo/*:: <bar> */(); |
|
react-docgen has some problems, but only because it relies on the fact that comments are attached as trailing on the decorator and not only as leading on the id of the class or the classbody. export default
@decorator
/** class description */
class A {}I guess this can be fixed somehow, although I can't see an easy solution, as there is no location recorded in the AST where the so in the case of export default /** Decorator description */ @decorator /** Description */ class /** Base */SomeName {}it is possible to know where the first comment belongs to, but it is not really possible to know which of the other two comments come before and which after the Any idea about this special case? It is the same case that broke in the past and whythis hack is present in react-docgen. |
|
In general the ruleset for the comment attachment make sense to me and I feel having it clearly defined is really good. I'm worried about the potential of breaking stuff and I think this change maybe should not be in a minor version. Not necessarily because of Babel users but for tools that use Babylon standalone. (As mentioned above) I haven't looked at the code changes so far. Will do it tomorrow. |
I think that we should add another rule:
This rule would change the behavior in cases like this one: if /* a */ (x) {}Currently It would also fix this case, where for (/* x */;;) {}Apart from that, I think that these rules are pretty good. We should write them somewhere else other than in this PR so that they don't get lost. I'll review the code later. export default /** Decorator description */ @decorator /** Description */ class /** Base */SomeName {}Special-casing that use-case would unfortunately break these: /**
* Class description
*/
@frozen class Foo {}
@frozen // Prevent modifications to the class
class Foo {} |
| // comments between nodes and these tokens automatically count as | ||
| // trailing comments. | ||
| groupEnd: | ||
| type === tt.bracketR || type === tt.braceR || type === tt.parenR, |
There was a problem hiding this comment.
Should we also add >, since it is used as a groupEnd for type parameters?
I think this would actually also help with the example I posted if i understood it correctly: /** leading on ExportDeclaration */
export default
/** leading on Decorator */
@decorator
/** inner on class because of class keyword between comment and identifier */
class /** leading on Identifier */SomeName
/** leading on body */
{}Is that correct? |
My aim with this change was to try to stay in the bounds of what we already do wherever possible.
The issue here is could serialize as any of technically. My preference for this patch is to leave the preference for comments to attach as leading comments on the next-closest node.
See below reply to @danez. This should be a trailing comment on the decorator, but it's a case I missed. I think this and the case above about
Yeah, I'm on the fence. I think partly it depends on how close we can get to the previous behavior. In an ideal worth, this patch would
You two have pointed out a big case I missed, so thanks a ton for that. I can also do another pass to see what cases might diverge from those 2 points. The logic I added around would place At the end of the day, if the only way to land this is a feature flag, I'm open to it, but I'd love to avoid that if at all possible. |
|
I'll reopen once I have an update. |
It's hard to say if this will affect anyone. The changes have the potential to cause comments to disappear if users use the new parser changes with the old
babel-traverse. That said, we've never provided much in the way of guarantees for comments anyway. Chances are, any complaints would be resolved by ensuring users have upgraded both core/traverse and the parser. In 99% of cases I'd expect those to all be updated at the same time anyway.This PR had one primary goal, which is to stop inserting comments into multiple locations in the AST. To do that though, I've tried to formalize a reasonable set of rules around how we attach comments in the first place, so people can have a reasonable intuition about it.
The rules come down to this:
node.startoffsetnode.startnode.startandnode.endrange of a nodeparent.end],)or},or;tokens on the same line as the node endFrom what I've seen, these rules seem very satisfactory and fit well with my own intuition. I'm curious what others think.