Skip to content

Commit 0e7677a

Browse files
zdenkoGeoffreyBooth
authored andcommitted
Fix #5046: Adjacent JSX (#5049)
* Fix #5046: Adjacent JSX * check CSX only when wrapped in parentheses * Fix indentation * Add test for unlikely, but valid, JSX syntax
1 parent 7cf739e commit 0e7677a

File tree

4 files changed

+53
-24
lines changed

4 files changed

+53
-24
lines changed

lib/coffeescript/nodes.js

Lines changed: 16 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/nodes.coffee

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -478,16 +478,21 @@ exports.Block = class Block extends Base
478478
# ensures that the final expression is returned.
479479
makeReturn: (res) ->
480480
len = @expressions.length
481+
[..., lastExp] = @expressions
482+
lastExp = lastExp?.unwrap() or no
483+
# We also need to check that we’re not returning a CSX tag if there’s an
484+
# adjacent one at the same level; JSX doesn’t allow that.
485+
if lastExp and lastExp instanceof Parens and lastExp.body.expressions.length > 1
486+
{body:{expressions}} = lastExp
487+
[..., penult, last] = expressions
488+
penult = penult.unwrap()
489+
last = last.unwrap()
490+
if penult instanceof Call and penult.csx and last instanceof Call and last.csx
491+
expressions[expressions.length - 1].error 'Adjacent JSX elements must be wrapped in an enclosing tag'
481492
while len--
482493
expr = @expressions[len]
483494
@expressions[len] = expr.makeReturn res
484495
@expressions.splice(len, 1) if expr instanceof Return and not expr.expression
485-
# We also need to check that we’re not returning a CSX tag if there’s an
486-
# adjacent one at the same level; JSX doesn’t allow that.
487-
if expr.unwrapAll().csx
488-
for csxCheckIndex in [len..0]
489-
if @expressions[csxCheckIndex].unwrapAll().csx
490-
expr.error 'Adjacent JSX elements must be wrapped in an enclosing tag'
491496
break
492497
this
493498

test/csx.coffee

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -771,11 +771,11 @@ test 'JSX fragments: fragment with text nodes', ->
771771

772772
test 'JSX fragments: fragment with component nodes', ->
773773
eqJS '''
774-
Component = (props) =>
775-
<Fragment>
776-
<OtherComponent />
777-
<OtherComponent />
778-
</Fragment>
774+
Component = (props) =>
775+
<Fragment>
776+
<OtherComponent />
777+
<OtherComponent />
778+
</Fragment>
779779
''', '''
780780
var Component;
781781
@@ -821,3 +821,20 @@ test '#5055: JSX expression indentation bug', ->
821821
{typeof a !== "undefined" && a !== null ? a : <span />}
822822
</div>;
823823
'''
824+
825+
# JSX is like XML, in that there needs to be a root element; but
826+
# technically, adjacent top-level elements where only the last one
827+
# is returned (as opposed to a fragment or root element) is permissible
828+
# syntax. It’s almost certainly an error, but it’s valid, so need to leave it
829+
# to linters to catch. https://github.com/jashkenas/coffeescript/pull/5049
830+
test '“Adjacent” tags on separate lines should still compile', ->
831+
eqJS '''
832+
->
833+
<a />
834+
<b />
835+
''', '''
836+
(function() {
837+
<a />;
838+
return <b />;
839+
});
840+
'''

test/error_messages.coffee

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,25 +1664,26 @@ test 'CSX error: invalid attributes', ->
16641664

16651665
test '#5034: CSX error: Adjacent JSX elements must be wrapped in an enclosing tag', ->
16661666
assertErrorFormat '''
1667-
render = ->
1667+
render = -> (
16681668
<Row>a</Row>
16691669
<Row>b</Row>
1670+
)
16701671
''', '''
16711672
[stdin]:3:4: error: Adjacent JSX elements must be wrapped in an enclosing tag
16721673
<Row>b</Row>
16731674
^^^^^^^^^^^
16741675
'''
16751676
assertErrorFormat '''
16761677
render = -> (
1678+
a = "foo"
16771679
<Row>a</Row>
16781680
<Row>b</Row>
16791681
)
16801682
''', '''
1681-
[stdin]:3:4: error: Adjacent JSX elements must be wrapped in an enclosing tag
1683+
[stdin]:4:4: error: Adjacent JSX elements must be wrapped in an enclosing tag
16821684
<Row>b</Row>
16831685
^^^^^^^^^^^
16841686
'''
1685-
16861687
test 'Bound method called as callback before binding throws runtime error', ->
16871688
class Base
16881689
constructor: ->

0 commit comments

Comments
 (0)