Skip to content
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

[CS2] Support for CSX - equivalent of JSX #4551

Merged
merged 12 commits into from
Jun 7, 2017
Merged

Conversation

xixixao
Copy link
Contributor

@xixixao xixixao commented May 16, 2017

So here's a fully functional implementation of what I call CSX - the JSX equivalent for CoffeeScript. I tried to adhere as much as possible to the syntactical rules of JSX (as opposed to doing possible fancy stuff).

First, let me address why I think it theoretically makes sense to include this in CoffeeScript:

  • To implement CSX properly, you need a fully functioning CoffeeScript parser. This is so difficult to do without using the actual implementation as it's practically impossible. Consider that https://github.com/jsdf/coffee-react-transform took over two years of development to get to its current state, with over 1200 lines of CS source code. This PR took me two nights and is adding 170 LOC to the compiler, while avoiding many issues that plagued the transform, f.e. Missing "unclosed tag" error on child nodes. jsdf/coffee-react-transform#56
  • JSX is immensely popular. Although I personally would not pick XML as role-model for anything, it has took off and is now used widely outside of React. It basically allows second compilation mode for some expressions. If CoffeeScript cannot support it, it's gonna be a major driver for people moving to ES6/7 with Webpack etc. toolchain (the only other really big thing CoffeeScript is missing is static typing, which might eventually be its final nail in the coffin).
  • JSX has real merits over custom runtime replacements in terms of syntax, mainly ease of textual content surrounding other expressions.

Second, I implemented this on top of 2, but the implementation would make it trivial to support it in original CoffeeScript too, provided we would have a way (option, pragma) to determine what target the CSX tags should compile to.

So how is this implemented and why: JSX is a super simple transform, provided you know you are looking at an expression in the surrounding language. Conceptually it works like this:

<div />  div()
<div x="a" />  div({x: 'a'})
<div>A</div> → div({}, 'A')

and so on. Of course React for example actually uses Something('div') instead of div(), but that doesn't really matter for the parsing phase. So I actually turn CSX into valid CoffeeScript tokens in the lexer. Note that some of the work could be done in the rewriter, the split between the lexer and the rewriter is very arbitrary, and I just found it easier to do this in the lexer, instead of having to pass bunch of information to the rewriter. But I think it would be doable to move most stuff outside of csxToken method there.

Once I do this conversion, it's actually tricky to tell which nodes were originally CSX. The Jison parser does not make it easy at all to pass adhoc info from the lexer to nodes (which compile the tree to JS), so I created a new token for the tag, and seed the info from there when compiling. The tagging of children nodes is not super clean, but I haven't done anything that wasn't at least a bit used before.

Now, for differences between JSX, coffee-react-transform and CSX:

  1. CSX doesn't support inline comments inside interpolations, same as JSX
  2. bare expressions as attribute values are not supported, same as JSX
  3. there is no support for custom pragmas, the compiler outputs JSX
  4. BREAKING CHANGE <x with leading space is no longer supported. Supporting this leads to highly ambiguous syntax:
x = a<b>c; # allowed
x = a <b> c; # syntax error, missing closing tag

both JSX and the transform handle this "correctly", allowing this code to be treated as comparison. I'm not sure that there is a way to allow this in CoffeeScript without making the resulting compilation ambiguous. JSX can do this easily, because a <b/> is not a valid JS epxression, but in CS it is simply a(<b/>). I think the transform looks ahead to determine whether there is a closing tag, and we could do something similar, but I don't know how to do that without introducing incorrect edge cases. Ideas welcome. (Update: I think restricting this to only unbalanced whitespace should alleviate most concerns)

You can see these in the tests I added. Note that I removed some original coffee-react-transform tests, which were mainly testing the CoffeeScript parsing, not the CSX part.

What's left?

Spreads, blocked by #3894
One case which is broken, which boils down to this being invalid CoffeeScript:

article({number: 2,
  range: 1,
},"\n")

(there is a corresponding CSX test with a TODO).

Fixes #4529.

@GeoffreyBooth
Copy link
Collaborator

This is very impressive. Thanks for making this effort!

If I could try to head off some expected critiques, if readers have an objection to whether JSX should be supported in the CoffeeScript ecosystem at all, please discuss that in #4529. For the purposes of this PR let’s please assume that CoffeeScript should support JSX, and let’s keep this thread to the specifics of this implementation.

Reading through what you’ve done, it seems obvious that the approach I had in mind in #4529, of trying to treat <s and >s essentially as backticks and then finding a way to update the compiler to allow backticks anywhere, would never work. It also seems obvious that the thought behind #4540, of building hooks for plugins, would be far too insufficient to achieve what you’ve done here. At first glance, at least, this appears to be the “full-assed” implementation that @jashkenas was referring to. Well done.

A few general questions before getting into specifics:

  1. How does this PR avoid the problems that doomed coffee-react-transform? Is it basically that this outputs JSX, whereas that project attempted to do what Babel’s React transform does and compile down to the React.createClass etc.?
  2. Is the only breaking change that now a space is required on either side of the < and > operators? (I can live with that.)
  3. How do these new tags interact with CoffeeScript’s comprehensions? Our comprehensions remain a big selling point over ES, and CSX working well with them would be a big reason to use CSX over JSX.
  4. How does indentation affect these tags? Or is it more or less irrelevant, since you know the hierarchy from the open and closing tags? Are we going to allow any indentation around the tags, and if so, how does that affect the code within them?
  5. How important are the TODOs? I assume we can live without the spread operator until ES: Allow deconstructing objects with splats #3894, as it’s not really part of JSX at all but rather a proposed ES feature that happens to be especially convenient in JSX; but are there any important parts of JSX that are unachievable until the TODOs are completed? Are there any future breaking changes that will happen when the TODOs get addressed? I’m wondering if this PR can be merged in as is, or if we need to treat it as work-in-progress until some of the TODOs are addressed, and if so, which ones.

@GeoffreyBooth GeoffreyBooth changed the title Support for CSX - equivalent of JSX [CS2] Support for CSX - equivalent of JSX May 16, 2017
@@ -1,4 +1,4 @@
/* parser generated by jison 0.4.17 */
/* parser generated by jison 0.4.13 */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow you don’t have the latest version of Jison installed. Please npm install.

src/lexer.coffee Outdated
@@ -48,6 +48,7 @@ exports.Lexer = class Lexer
@seenExport = no # Used to recognize EXPORT FROM? AS? tokens.
@importSpecifierList = no # Used to identify when in an IMPORT {...} FROM? ...
@exportSpecifierList = no # Used to identify when in an EXPORT {...} FROM? ...
@includesCSX = no # Used to optimize CSX checks
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, all comments should be complete sentences and end in periods. This makes the annotated source feel, well, annotated, like there is normal written commentary accompanying the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two lines above need fixing then .)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes they do. They should also get some backticks, as they’re treated as Markdown when getting converted into the annotated source. I’ve generally been fixing comments as I come across them, rather than taking the time to go through all the code from top to bottom, so there are plenty of bad examples waiting to be fixed. All I’m asking you is to not add to the list of comments to correct 😄

test/csx.coffee Outdated
@@ -0,0 +1,616 @@
# We usually do not check the actual JS output from the compiler, but since
# CSX is not readily supported by Node, we do it in this case
eqCSX = (cs, js) ->
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There’s already a toJS function in global scope. Can we please just use it, and follow the pattern of the modules tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GeoffreyBooth is that boilerplate useful? I find the tests easier to read without it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just keeps things DRY, and ultimately we’re trying to keep the codebase internally consistent. Not everything in there is done the way I’d prefer either.

unquote: (literal) ->
unquoted = @value[1...-1]
if literal
unquoted.replace /\\n/g, '\n'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain what's special about the newlines here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xixixao Could you please reply to this, and also explain what’s going on with the escaping here. Per @lydell’s earlier comment, why is the escaping so simple? Why can we ignore things like escaped backslashes?

Copy link
Contributor Author

@xixixao xixixao May 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the (now outdated) comment below.

src/nodes.coffee Outdated
unquoted = @value[1...-1]
if literal
unquoted.replace /\\n/g, '\n'
.replace /\\"/g, '"'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dealing with backslashes is never this simple. What if the backslash is already escaped? \\"

Copy link
Contributor Author

@xixixao xixixao May 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We format strings to JS strings, which means escaping new lines and quotes. This function removes it, so the string's content is printed out literally.

"b\\"a" throws syntax error, so that can never happen.

test/csx.coffee Outdated

# Unlike in coffee-react-transform
test 'bare numbers not allowed', ->
throws -> CoffeeScript.compile '<div x=3 />'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to see what the error messages look like for these, and move the tests to error_messages.coffee

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no reason to have these test both here and in error_messages.coffee, is it?

@lydell
Copy link
Collaborator

lydell commented May 16, 2017

Random thoughts:

  • Would coffeelint be able to create CSX lint rules, without bending over backwards trying to differentiate CSX from function calls or something?
  • What are error messages for mistakes in CSX like?
  • Could any problems arise when combining literate CS and CSX?
  • I think JSX has special string escaping rules which we need to test, but I can't remember them right now.

@xixixao
Copy link
Contributor Author

xixixao commented May 16, 2017

@GeoffreyBooth

... full-assed ...

Correct on all points.

  1. How does this PR avoid the problems that doomed coffee-react-transform? Is it basically that this outputs JSX, whereas that project attempted to do what Babel’s React transform does and compile down to the React.createClass etc.?

No, I think the main troubles came from a custom parser that was independent of CoffeeScript. Outputting JSX mainly simplifies the job of escaping stuff (since the escaping/unescaping will be done by the JSX transform).

  1. Is the only breaking change that now a space is required on either side of the < and > operators? (I can live with that.)

Yes, I think so. To this change: at least it's quite unlikely that you will have code that previously compiled compile to something else. So it is a breaking change, but most people will be able to easily fix it.

  1. How do these new tags interact with CoffeeScript’s comprehensions? Our comprehensions remain a big selling point over ES, and CSX working well with them would be a big reason to use CSX over JSX.

There is nothing special in regards to comprehensions. You can use attribute strings without wrapping (currently broken, will fix and add a test).

  1. How does indentation affect these tags? Or is it more or less irrelevant, since you know the hierarchy from the open and closing tags? Are we going to allow any indentation around the tags, and if so, how does that affect the code within them?

You can see from the first TODO that indentation matter. After all, the tags are treated as object literal arguments. There might be a way to filter the indentation out, so it doesn't cause problems, but I don't think it's important to allow any formatting. CoffeeScript is an indentation based syntax, you should not expect CSX to suddenly ignore whitespace.

  1. How important are the TODOs? I assume we can live without the spread operator until ES: Allow deconstructing objects with splats #3894, as it’s not really part of JSX at all but rather a proposed ES feature that happens to be especially convenient in JSX; but are there any important parts of JSX that are unachievable until the TODOs are completed? Are there any future breaking changes that will happen when the TODOs get addressed? I’m wondering if this PR can be merged in as is, or if we need to treat it as work-in-progress until some of the TODOs are addressed, and if so, which ones.

Spread is part of the JSX syntax and requires special support. Note that <div a="x" {...props}> will compile via div({a: "x", ...props}), the curlies need to be accounted for and stripped. It's also pretty widely used and hence important. But I don't want to add it until there is support for object spreads in CoffeeScript AST. The only other TODO is the indentation bug, otherwise this is complete JSX as far as I am aware (there might be some missing edge cases, help welcome). This PR should be mergeable as is, if we want this in the language.

@lydell

  1. Would coffeelint be able to create CSX lint rules, without bending over backwards trying to differentiate CSX from function calls or something?

There's a linter for ES with JSX too, right? Should be doable.

  1. What are error messages for mistakes in CSX like?

I will add this to the tests, but in short, they are pretty:

error: expected corresponding CSX closing tag for bad
<div><bad></div>
      ^^^

I modelled the new errors I added after JSX errors, although the attribute one is prettier than JSX:

error: expected wrapped or quoted CSX attribute
<div x=f(3) />
       ^
  1. Could any problems arise when combining literate CS and CSX?

Literate CS uses indentation no? Shouldn't be a problem.

  1. I think JSX has special string escaping rules which we need to test, but I can't remember them right now.

There are some tests for this ported over from coffee-react-transform. I am essentially passing everything through and allowing JSX to deal with this.

@jashkenas
Copy link
Owner

This is indeed, the sort of "full-assed" support I was hoping for. Congrats!

For what it's worth, I still think that CoffeeScript, as a concept, is made weaker by including JSX than leaving it out.

But that said, if you fine folks want to put it in 2.0, this sort of patch is the way to do it.

One note: Wouldn't it be better (and more harmonious) to have CSX leave out closing tags, and simply use CoffeeScript's significant whitespace to close all CSX tags?

@GeoffreyBooth
Copy link
Collaborator

GeoffreyBooth commented May 16, 2017

Wouldn’t it be better (and more harmonious) to have CSX leave out closing tags, and simply use CoffeeScript’s significant whitespace to close all CSX tags?

I like this idea. If we’re going to support JSX output, we might as well try to improve it (safely) however we can, just as we try to improve some of JavaScript’s rough edges. And I really want CSX to fit in with CoffeeScript’s overall use of significant whitespace, and not be another feature like chaining that creates a whitespace-insignificant zone in the middle of otherwise sensible code.

I wonder if we could also find an alternate syntax that doesn’t use < or >, like Jade, but that’s probably going too far to save us from two difficult-to-type characters. At least if the indentation closes them for me, that saves me from typing half as many of them 😄

@xixixao xixixao force-pushed the csx branch 3 times, most recently from b00697a to ef1b8ba Compare May 16, 2017 20:47
@xixixao
Copy link
Contributor Author

xixixao commented May 16, 2017

Updates to code: Fixed comment. Used toJS. Added tests to errorMessages. Fixed error in identifier regex that cause <2 to be valid tag name (so this limits the breaking change to only <idenfitier, <42 is still valid). Fixed interpolation inside attribute values, added test case for it.

^^
'''

test "csx error: ambigious tag-like expression", ->
Copy link
Collaborator

@lydell lydell May 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ambiguous

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean ambiguous? 😆

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! (Looks like I edited by comment too late 😀)

test/csx.coffee Outdated
test 'ambigious tag-like expression', ->
throws -> CoffeeScript.compile 'x = a <b > c'

test 'ambigious tag', ->
Copy link
Collaborator

@lydell lydell May 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ambiguous

@xixixao
Copy link
Contributor Author

xixixao commented May 16, 2017

@jashkenas I considered using whitespace. But there are theoretical and practical reasons not too. Theoretical:

  1. JSX is verbose even for JS. Is there a point in trying to make it less verbose? It's verbosity is kinda the point of it (i.e. "designers" can use it, it's 1:1 with HTML, etc.)
  2. CS2 is trying to match ES7+. JSX is a feature of the ES7+ ecosystem. With this approach you can tell people: You can now use CSX just like you would use JSX, just swap CS for JS and rest is the same.

Practical:

  1. It just doesn't work well. Consider the following very simple snippet:
<div>
  <div>Title</div>
  <div className="bla">
    Hello
  </div>
  world
</div>

Now based on indent:

<div>
  <div>Title</div>
  <div className="bla">
    Hello
  world

Now you could play with the rules and come up with some variations, but they will all be confusing/ambiguous/inconsistent.

Think of JSX as heredocs (which is also, coincidentally, how I implemented it). You wouldn't want to use indentation there either, you also use delimiters

"""Hello #{
  f(x)
} something"""

@GeoffreyBooth
Copy link
Collaborator

@xixixao the next time you commit, can you please not force-push or amend? It’s easier to review this if each revision is a separate commit. All the commits will get squashed together when we merge the PR into 2, so the history on your branch doesn’t matter.

@jashkenas
Copy link
Owner

@xixixao — While I'm not persuaded in the least by your two theoretical reasons, I am moved by your practical one:

It just doesn't work well.

I would love to see a sampler of 3-5 real-world examples of reasonable JSX templates, done in closed-tag and significant-whitespace styles. You may very well be right, but it would be worth evaluating.

@xixixao
Copy link
Contributor Author

xixixao commented May 16, 2017

@GeoffreyBooth Github n00b, will do

…r regex, fixed interpolation inside attributes value and added test
@xixixao
Copy link
Contributor Author

xixixao commented May 16, 2017

@GeoffreyBooth fixed, sorry about that.

@helixbass
Copy link
Collaborator

@xixixao @jashkenas @GeoffreyBooth @lydell I didn't see this until now, I've also been working on JSX-in-Coffeescript this week. I'll take a look at @xixixao's implementation but seems like I took a different approach: in addition to normal JSX syntax, there are whitespace-indented syntaxes (basically HAML) and it lexes differently inside of JSX elements but creates tokens and has grammar rules for them. To me that's more Coffeescript-y (it's certainly what I want for the same reasons I love Coffeescript) and I'm not surprised by @jashkenas' comment to that effect. I'll open a pull request as well (though I wasn't sure if merging it into Coffeescript proper (1.x or 2) would be the way to go, whether b/c of breaking changes, philosophical objections, ...)

@GeoffreyBooth
Copy link
Collaborator

@helixbass thanks! It’s a shame that people are duplicating effort, but this makes clear just how in-demand this feature is. I’m more convinced than ever that we need to support JSX in a non-hacky way.

Please target the 2 branch. I’m trying to consider the 1.x line as more-or-less retired except for important bugfixes. I don’t want the burden of trying to maintain two branches. Also we need more reasons for people to upgrade 😄

@helixbass and @xixixao it might be worth looking at the Coffee Tags PR. It was an attempt to support a JSX-like syntax that used significant whitespace, and compiled out to Vue or React.

@GeoffreyBooth
Copy link
Collaborator

Time to write the documentation for this. Anyone want to volunteer what it should be? Or at least what the example in the docs should be? Ideally it would be something that shows moderately complicated JSX, but takes advantage of one or more of CoffeeScript’s unique features such as array comprehensions.

@DanielRamosAcosta
Copy link

I have this component in my experimental project, if it's useful to you. It renders a rating like this:

image

@GeoffreyBooth
Copy link
Collaborator

@DanielRamosAcosta I’m trying to reduce your component to a short example. Can you tell me if this is correct?

renderStarRating = ({ rating, maxStars }) ->
  <aside title={"Rating: #{rating} of #{maxStars} stars"}>{
    for wholeStars in [0...Math.floor(rating)]
      <Star className="wholeStar" />
    if rating % 1 isnt 0
      <Star className="halfStar" />
    for emptyStars in [Math.ceil(rating)...maxStars]
      <Star className="emptyStar" />
  }</aside>

@DanielRamosAcosta
Copy link

I'm only getting empty stars with that code... I'm looking into it

@lydell
Copy link
Collaborator

lydell commented Jun 20, 2017

(A lesser known feature of CoffeeScript is that you can leave out the foo in part of for loops if you don't need it:

for [1..3]
  do knock

)

@DanielRamosAcosta
Copy link

@GeoffreyBooth I've written some unit tests for my component and refactor with some of your improvements. The component you proposed I think it should be something like this:

renderStarRating = ({ rating, maxStars }) ->
  <aside title={"Rating: #{rating} of #{maxStars} stars"}>
    {for wholeStar in [0...Math.floor(rating)]
      <Star className="wholeStar" key={wholeStar} />}
    {if rating % 1 isnt 0
      <Star className="halfStar" />}
    {for emptyStar in [Math.ceil(rating)...maxStars]
      <Star className="emptyStar" key={emptyStar} />}
  </aside>

@GeoffreyBooth
Copy link
Collaborator

I see you use many more braces, which I was hoping to avoid. Are they necessary to get it to work?

@DanielRamosAcosta
Copy link

Yes 😢 , React only renders the return value of each statement inside the braces...

@GeoffreyBooth
Copy link
Collaborator

GeoffreyBooth commented Jun 21, 2017

Okay, I’ve updated my example: https://rawgit.com/GeoffreyBooth/coffeescript/2-docs/docs/v2/#jsx

renderStarRating = ({ rating, maxStars }) ->
  <aside title={"Rating: #{rating} of #{maxStars} stars"}>
    {for [0...Math.floor(rating)]
      <Star className="wholeStar" />}
    {if rating % 1 isnt 0
      <Star className="halfStar" />}
    {for [Math.ceil(rating)...maxStars]
      <Star className="emptyStar" />}
  </aside>

Does this work?

@DanielRamosAcosta
Copy link

That works, but you'll get React warnings becouse when you render arrays it is required to asign the "key" prop to the component. This is the warning:

Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using <aside>. See https://fb.me/react-warning-keys for more information.

@GeoffreyBooth
Copy link
Collaborator

Man, this is becoming a messy example then. I was hoping to use a loop comprehension with JSX, because loop comprehensions are something that ES lack (though .forEach or .map come close) and therefore we could demonstrate an advantage of CSX over JSX. But this is looking overly complicated. Any ideas for anything simpler?

@askucher
Copy link

@microdou
Copy link

microdou commented Jul 6, 2017

@GeoffreyBooth
Great that CSX and destructuring object spreads finally get merged into beta3!
However, spreads inside csx brakets (<div a="x" {props...}></div>) are not working yet, still throwing error.

@zdenko
Copy link
Collaborator

zdenko commented Jul 7, 2017

@xixixao @GeoffreyBooth
Not sure how should this compile.
In JSX this

// props = {id: "a", title: "some title"}
<div {...props}></div>

compiles to

<div id="a" title="some title"></div>

I don't have much experience with JSX, but it seems that <div {Object.assign({},props)}></div> will not work (example).

@GeoffreyBooth
Copy link
Collaborator

Could we just compile

<div a="x" {props...}></div>

to

<div a="x" {...props}></div>

? Is that really an object spread in there, as opposed to generic spread syntax like we’d find in function parameters or an array?

@zdenko
Copy link
Collaborator

zdenko commented Jul 7, 2017

I was thinking the same.
In React (and probably other libraries) <div {...props}></div> is compiled to React.createElement("div", props);.

@microdou
Copy link

microdou commented Jul 7, 2017

@GeoffreyBooth
It seems like {...props} inside <> in JSX is a special notation different from the ES6 generic spread syntax.
<div {...props, a: "x"} /> or <div {...props1, ...props2} /> don't work in JSX.
<div {...props1} {...props2} /> works in JSX.
You are right: a special treatment to {props...} inside <> of CSX is the way to go.

@microdou
Copy link

microdou commented Jul 7, 2017

Here is a summary to the spread syntax in JSX and CSX.

JSX:

// Spread the whole props object
<div {...props} />
// Spread two props objects
<div {...props1} {...props2} />
// Spread an updated props object
newProps = {...props, a: "x"}
<div {...newProps} />
// Spread an updated props object within <>, not reliable, not recommended
<div { ...{...props, a: "x"} } />
// Not supported. Currently wrong syntax
<div {...props, a: "x"} />
// Not supported. Currently wrong syntax
<div {...props1, ...props2} />

Accordingly, CSX may deal with the following :

# Spread the whole props object
<div {props...} />
# Spread two props objects
<div {props1...} {props2...} />
# Spread an updated props object
newProps = {props..., a: "x"}
<div {newProps...} />
# Spread an updated props object within <>, not reliable, not recommended
<div { {props..., a: "x"}... } />
# Not supported. Currently wrong syntax
<div {props..., a: "x"} />
# Not supported. Currently wrong syntax
<div {props1..., props2...} />

@GeoffreyBooth
Copy link
Collaborator

Implemented via #4607.

@GeoffreyBooth GeoffreyBooth modified the milestone: 2.0.0 Aug 14, 2017
@askucher
Copy link

askucher commented Aug 15, 2017

Did you try https://github.com/askucher/lsxc ?

Pug/Jade like syntax

@GeoffreyBooth
Copy link
Collaborator

Looks like this really works: https://iainhouston.com/blog/exploring-react-with-coffeescript-2.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants