-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix #5046: Adjacent JSX #5049
Fix #5046: Adjacent JSX #5049
Conversation
What about this case? render = -> (
<Row>ABC</Row>
<Row>DEF</Row>
) The parentheses get removed as redundant, and then var render = function() {
return (
<Row>ABC</Row>;
<Row>DEF</Row>;
)
} Curiously though, this is the error:
|
Also, this: render = ->
<Row>ABC</Row>
<Row>DEF</Row> should compile, as it would become this: var render = function() {
<Row>ABC</Row>;
return <Row>DEF</Row>;
} which is valid JSX. |
User from #5034 wants this JSXFunction = -> (
<Row>ABC</Row>
<Row>DEF</Row>
) to compile into this JSXFunction = function() {
return <Row>ABC</Row>
<Row>DEF</Row>;
}; But, this is an error. Your PR solved this, but was to greedy and was throwing and error even if render = -> (
<Row>ABC</Row>
return <Row>DEF</Row>
) My PR only corrects greediness. |
Besides, this render = ->
<Row>ABC</Row>
<Row>DEF</Row> already compiles on the render = function() {
<Row>ABC</Row>;
return <Row>DEF</Row>;
}; |
The non-parentheses version compiles today in 2.3.0, but my PR made it break. It should compile, because it’s valid JSX. |
OK, So only JSX in parentheses should throw an error? render = -> (
<Row>ABC</Row>
<Row>DEF</Row>
) Since CS removes parentheses in any case, JSX will get special treatment. And, what about this case? render = -> (
a += 1
<Row>ABC</Row>
<Row>DEF</Row>
) I guess we could inspect expressions in the parentheses and only if JSX is present we would throw an error. |
I’m not sure what to do. I just want to make sure we at least don’t throw errors on valid JSX. |
The only way I see is checking parentheses. |
The last commit fixes cases discussed above. Valid CSX: render = ->
<Row>ABC</Row>
<Row>DEF</Row>
###
render = function() {
<Row>ABC</Row>;
return <Row>DEF</Row>;
};
### <a></a>
foo <b></b>
###
<a></a>;
foo(<b></b>);
### Compiler throws an error when adjacent CSX in parentheses is not wrapped in an enclosing tag. render = -> (
<Row>ABC</Row>
<Row>DEF</Row>
)
###
error: Adjacent JSX elements must be wrapped in an enclosing tag
<Row>DEF</Row>
^^^^^^^^^^^^^
### Only last two expressions are checked. render = -> (
a = 2
<Row>ABC</Row>
<Row>DEF</Row>
)
###
error: Adjacent JSX elements must be wrapped in an enclosing tag
<Row>DEF</Row>
^^^^^^^^^^^^^
### This will compile. render = -> (
<Row>ABC</Row>
a = 2
<Row>DEF</Row>
)
###
render = function() {
var a;
<Row>ABC</Row>;
a = 2;
return <Row>DEF</Row>;
};
### |
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.
LTGM. @vendethiel?
I think even the non-parenthesized version should break. It will never be what the user meant, Afaik. The way CoffeeScript works makes this a bit ambiguous maybe... I think we had a similar thing with
|
Agree. Even the user from #5034 expected something else. render = ->
x = 1
y = 2
<Row>ABC</Row>
<Row>DEF</Row> I think in such cases we should return the last expression, e.g., no error. |
So what else needs to be done to wrap up this PR? |
As per @vendethiel's suggestion, I would treat render = ->
<Row>ABC</Row>
<Row>DEF</Row> in the same way as render = -> (
<Row>ABC</Row>
<Row>DEF</Row>
) However, this case would return the last expressions render = ->
x = 1
y = 2
<Row>ABC</Row>
<Row>DEF</Row>
###
render = function() {
var x, y;
x = 1;
y = 2;
<Row>ABC</Row>;
return <Row>DEF</Row>;
};
### |
Isn’t that the current behavior before we started changing things? |
@GeoffreyBooth it was, but then your PR changed it and in this PR you commented that non-parenthesized JSX should compile. |
Right, so what's the difference between this PR and reverting mine? |
Why? I don't think that makes sense. |
@vendethiel It's valid coffee/js/jsx code and coffee implicitely returns the last statement of a function body. JSX tags are still only js objects. I don't see the need for special treatment either but it's true that it's unlikely that the user ment for the code to turn out that way.
|
->
<a></a>
foo
<b></b> Your PR:
This PR: (function() {
<a></a>;
foo;
return <b></b>;
}); |
@zdenko I get that, what I mean is, what's the difference between current 2.3.0 (a.k.a. reverting my PR to the prior state of |
In general I'd agree -- that's the role of a linter. But here we're just copying an error that's reported by babel; because the error is lost when compiling. |
The error isn’t lost; there’s a difference between var render = function() {
return (
<Row>ABC</Row>
<Row>DEF</Row>
)
} and var render = function() {
return (
<Row>ABC</Row>;
<Row>DEF</Row>;
)
} The version without the semicolons throws the Babel error, while the other doesn’t. Since CoffeeScript always adds the semicolons for each new line, we shouldn’t ever get that error. |
I get an error on Babel for var render = function() {
return (
<Row>ABC</Row>;
<Row>DEF</Row>;
)
} This works var render = function() {
return (
<Row>ABC</Row>,
<Row>DEF</Row>
)
} If we revert your PR and merge this one, we'll (currently) get an error only if JSX in enclosed in parentheses. -> (
<a></a>
<b></b>
)
###
[stdin]:4:4: error: Adjacent JSX elements must be wrapped in an enclosing tag
<b></b>
^^^^^^
### Non-parenthesized JSX will compile: ->
<a></a>
<b></b>
###
(function() {
<a></a>;
return <b></b>;
});
### |
Okay, so regarding what would trigger an error in this PR: -> (
<a></a>
<b></b>
) That’s equivalent to this JS: (function() {
return (
<a></a>;
<b></b>;
);
}); Which throws this error in Babel:
Which isn’t really equivalent to “Adjacent JSX elements must be wrapped in an enclosing tag.” Do we care? |
It’s not equivalent because of our everything-is-an-expression semantics. I think we do care. |
Maybe “do we care” is a bit harsh 😄 I guess the question is what we consider (
<a />
<b />
) to be equivalent to, since it is an expression. Some more ways of putting it, in JS, with the errors from Babel: var someJsx = (
<a />
<b />
);
and var someJsx = (
<a />;
<b />;
);
and finally, var someJsx = (
<a />,
<b />
); compiles successfully, into var someJsx = (React.createElement("a", null), React.createElement("b", null)); So in CoffeeScript, each newline triggers a semicolon; and there doesn’t seem to be an equivalent for the comma operator or a way to trigger its output. (This is worth reading.) I think Babel’s |
We do have the comma operator, just spelled For us, |
So @vendethiel what’s the bottom line here? Can we merge in this PR as is, or does it need any further changes? |
@@ -1664,25 +1664,26 @@ test 'CSX error: invalid attributes', -> | |||
|
|||
test '#5034: CSX error: Adjacent JSX elements must be wrapped in an enclosing tag', -> | |||
assertErrorFormat ''' | |||
render = -> | |||
render = -> ( |
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 think we should test that it errors out both with and without parens
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.
But the without-parens version is valid JSX:
->
<a />
<b />
(function() {
<a />;
return <b />;
});
(function () {
React.createElement("a", null);
return React.createElement("b", null);
});
I agree it’s likely a mistake on the user’s part, but catching “most of the time this is wrong” errors is the job of a linter, not the compiler.
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 talked about this a bit earlier.
You could say that, but you could also say that
->
<a />
<b />
really is
->
return (
<a />
<b />
)
just like
->
a: 1
b: 2
is
->
return {
a: 1
b: 2
}
instead of
->
{a: 1}
return {b: 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.
I don’t think you could say that parentheses are implied. JSX tags on subsequent lines aren’t assumed to be part of a unified construct the way an object is. They don’t compile into a single entity, for one thing, even with parentheses:
jsx = (
<a />
<b />
)
jsx = (<a />, <b />);
That’s not the way objects behave. The separate keys of an object are unified by virtue of being all part of the same block, as defined by indentation. Adjacent JSX tags are just that, adjacent JSX tags, unless they’re enclosed by a parent tag or fragment.
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.
OK. I also want to point out that this:
I agree it’s likely a mistake on the user’s part, but catching “most of the time this is wrong” errors is the job of a linter, not the compiler.
Could very well apply to the original warning. Babel could compile it to two createElement doing nothing.
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 very well apply to the original warning. Babel could compile it to two createElement doing nothing.
It could, but the JSX spec tells it not to. I think that's the distinction.
<Row>a</Row> | ||
<Row>b</Row> | ||
) | ||
''', ''' | ||
[stdin]:3:4: error: Adjacent JSX elements must be wrapped in an enclosing tag | ||
[stdin]:4:4: error: Adjacent JSX elements must be wrapped in an enclosing tag | ||
<Row>b</Row> | ||
^^^^^^^^^^^ |
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.
@zdenko We should also add a test for the non-error case:
->
<a />
<b />
That would be a good place to put a comment with a link to this PR, and an explanation for why this shouldn’t error.
# Conflicts: # test/csx.coffee
@zdenko @vendethiel I added the last test that I had requested. I’m eager to wrap this up. Any more notes? |
@GeoffreyBooth LGTM |
Fixes the issue in previous PR (#5046).
In
Block::makeReturn
, the last two expressions are checked before the main loop starts.Instead of
unwrapAll()
, I usedunwrap()
to avoid false errors withfoo <a></a>
and when explicitreturn
is used.