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

Use tink_hxx for parsing #95

Closed
wants to merge 5 commits into from
Closed

Conversation

back2dos
Copy link

This replaces the parser and AST by the counterparts from tink_hxx, to get accurate position tracking.

Among other things, this deals with mismatched tags more gracefully and allows for autocompletion without $:

npminstall

I also added some rudimentary props checking for components (both functions and classes) and warnings for unknown entities:

props

There's no checking for spreads, nor for missing props (this could be improved to some degree) nor for plain HTML tags. The default generator in tink_hxx does the former two, but it requires some quite heavy macros.

I suppose the sane thing to do would be to extract the hxx generator from coconut.react into a standalone thing, so that you can just use jsx or hxx in react projects, depending on your preferences/needs.

As for prop checking HTML tags, I want to extract the DOM spec from js-virtual-dom, so that it can be used everywhere. I just have to determine how to deal with all of React's idiosyncrasies (synthetic events, camel case handlers, altered onChange semantics).

Anyway, let me know what you guys think ;)

@elsassph
Copy link
Contributor

Legendary!

Can I complain about the lack on code style consistency? You have a cool style but it's a bit out of place :)

@back2dos
Copy link
Author

I don't mind your complaints, but what would help the most would be if you went ahead and squeezed it into the shape that pleases you the most. If I do it, neither of the both of us will be really happy with the result :D

@kLabz
Copy link
Contributor

kLabz commented Feb 27, 2018

Now that's awesome 🎉

Would it be possible to handle jsx('<$MyComponent />') too?
Its is not fully retro-compatible atm because of this (and maybe other things too, I need to remove all these $ to see the errors if any :D).

Edit:
A little sed later, I still have a lot of errors:

  • Some unrecognized props, mainly wrapper components accepting props and passing the rest of the props to the wrapped component, which is not known by the wrapper. Hard to type =/
  • Cannot access field or identifier onClick for writing for jsx('<AddProjectButton onClick=${createProject} />');
  • Identifier expected for key=$0; this syntax was allowed before

@back2dos
Copy link
Author

Sure. What's that supposed to do though? Maybe it'd be best to add a test for that.

@kLabz
Copy link
Contributor

kLabz commented Feb 27, 2018

Those are the same in current jsx:

  • <$MyComponent /> and <MyComponent />
  • <MyComponent key=$1 />, <MyComponent key=${1} /> and <MyComponent key={1} /> (or <MyComponent key=$one /> if one as a value of 1)

@back2dos
Copy link
Author

Ok. I'll have to alter the parser to accept that syntax. Out of curiosity: could you explain why it exists though?

I get the point of <MyComponent key=${1} /> (it's Haxe interpolation syntax) and <MyComponent key={1} /> (it's actual JSX syntax and compatibility doesn't hurt). I don't get <MyComponent key=$1 /> (it's neither of both) nor <$MyComponent /> (does it maybe trigger autocompletion or something)?

@kLabz
Copy link
Contributor

kLabz commented Feb 28, 2018

Got it working for my current project; I had to:

  • Change <$MyComponent /> to <MyComponent /> everywhere
  • Change a few key=$0
  • Fix a src="${state.url}" that should not have existed. I got no error for that, but it did not resolve to state.url (which is expected, I guess)
  • Add props typing for a simple functional component that was using type inference (that's where "Cannot access field or identifier onClick for writing" was coming from, maybe this could be catched somehow?)
  • Use Dynamic for a wrapper component's props (I couldn't even do T:MyProps because of some optional field), that's the only change that bothered me but there may be another solution here

Overall that's impressive that I had to change so few to make my project work with a complete jsx rewrite. Even more impressive is that most of it is due to the syntax I used, which -I guess- is not the most widely used since it's the less jsx-like one.

I think the new syntax is better (closer to actual jsx, and that's a good thing if we want to convert some reactjs developers to haxe), but it's a breaking change for some.

Maybe adding support for this syntax under a compilation flag (yeah, I know..) for those that used it would allow for more retro compatibility while defining the "default" syntax of haxe-react jsx as close as reactjs jsx as possible? Or just drop it and bump a major version with a breaking change :)

This syntax came from standard haxe interpolation, which accepts both 'aa${b}aa' and aa $b aa. I mainly use it for completion and syntax highlighting (since I have no support for jsx atm), and it's not a big deal to drop it.

@elsassph
Copy link
Contributor

elsassph commented Feb 28, 2018

The point of the $ syntax is completion, expression coloring, and code navigation: we have many IntelliJ users and being able to Ctrl+Click a tag to go to the class declaration is a must have for our teams.

It'd be amazing to add support for it, but by all mean, you can enable it only with a compiler flag.

(hum, that's what Rudy said with more words :))

@zabojad
Copy link

zabojad commented Mar 1, 2018

Hi guys! It might be completely out of the current subject but do you think we could have conditional compilation instructions support right into jsx :p?

    return jsx('
        <div>
            <div>...</div>
#if something
            <div>specific for my something context</div>
#end
            <div>some other thing...</div>
        </div>
    ');

Yhea... My wishes have no limit ^^...

@zabojad
Copy link

zabojad commented Mar 1, 2018

Thinking about it, there is also this which is allowed in normal JSX (ES6) and which is quite useful:

    <div>
        ...
        (someCondition && <span>loading...</span>)
        ...
    </div>

Do you think we could/should do that ?

@back2dos
Copy link
Author

back2dos commented Mar 1, 2018

@zabojad that particular syntax for conditional rendering won't work, because it requires the parser to be reentrant, which is really tricky. However, tink_hxx can parse if statements (although that's disabled in this PR), so you can write:

<if {someCondition}>
  <span>loading...</span>
</if>

As for conditional compilation, it probably could be done too, but I'll have to think about it.

@zabojad
Copy link

zabojad commented Mar 1, 2018

@back2dos hey nice feedback! I was more expecting a "naaa, that won't be possible" ^^...

Just for the sake of not moving too far away from the "original" JSX syntax, do you think we could keep the () to wrap the if statements? Can writting the if be optional? Would ternary statements be allowed?

If not, it's not a big deal, I'm just trying to make the transition from ES6-react to haxe-react the smoother as it can be for new developers to come onboard...

@kLabz
Copy link
Contributor

kLabz commented Mar 1, 2018

someCondition [too] often being anything but a real boolean, they'll have to adapt anyway :)

@zabojad
Copy link

zabojad commented Mar 1, 2018

@kLabz agreed but that would easily translate to:

    ( something != null && <div>...</div> )

That's more a js vs haxe-js difference...

@back2dos
Copy link
Author

back2dos commented Mar 1, 2018

Bringing JS truthiness to Haxe wouldn't be hard.

As opposed to that, having tags within expressions requires parser reentrancy and I have tried for almost two weeks to get that right, and once it started working decently, I realized that there's no way to get completion. So for the time being, I don't see that happening.

@zabojad
Copy link

zabojad commented Mar 1, 2018

I'm not sure we need js truthiness in haxe...

OK for the parser reentrancy issue. It's already nice if we can have if statements in the JSX. I was just worrying about <if {someCondition}> not being JSX syntax but I think a little note in the README into the section "haxe JSX vs normal JSX" will do it...

Thanks for this very nice peace of work @back2dos !

@kLabz
Copy link
Contributor

kLabz commented Mar 2, 2018

Another change (for the best, imo) is that this allows attributes without values, such as <input autoFocus /> 👍

@back2dos
Copy link
Author

back2dos commented Mar 4, 2018

Ok, so a few updates:

  1. Haxe 4 support.
  2. Support for if, for and switch. See test and docs.
  3. Support for <$Tag>. While it does trigger auto completion, jump to definition doesn't work. Maybe @nadako can help?

@djaonourside
Copy link

djaonourside commented Mar 12, 2018

@back2dos, is it possible to implement go to definition functionality without typing ' $' before component? It also would be great to have component auto import feature.

@back2dos
Copy link
Author

@djaonourside I would think so, but there's nothing we can do about it from this libraries's side. The code the macro generates tracks positions accurately.

It comes down to the IDE to support that. IntelliJ for example implements all Haxe support separately, so it will have to replicate all this logic. VSCode could support jumping to definition, but the plugin would have to understand that the opening tag is actually to be treated as expression (interestingly it even fails with <$Tag which may be fixable in the macro code). Also VSCode does not do auto import in general, so it won't work in JSX in particular either. And then there's FD which just generally doesn't seem to play too well with macros.

@nadako
Copy link

nadako commented Mar 12, 2018

Hmm, IIRC for the VS Code extension we just ask the position from the compiler without doing any magic, so in theory it should work as long as the expression under the cursor is sensible for "go-to definition" (e.g. a field, local var, new expr, etc).

@djaonourside
Copy link

djaonourside commented Mar 12, 2018

@nadako
Unfortunately, it really doesn't work. Maybe the extension doesn't recieve full path of component class?
img1

var fields = [
{field: "@$__hx__$$typeof", expr: macro untyped __js__("$$tre")},
var fields:Array<ObjectField> = [
{field: #if (haxe_ver < 4) "@$__hx__$$typeof" #else "$$typeof", quotes: DoubleQuotes #end, expr: macro untyped __js__("$$tre")},
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't it be quotes: Quoted instead?
HaxeFoundation/haxe@b6e5d66

@elsassph
Copy link
Contributor

Please rebase - unit tests have been fixed (get latest munit), Travis CI set up.

@elsassph
Copy link
Contributor

PS: what is about "FD doesn't play well with macros"? Things have improved on that front a little while go, like addition of compiler-based code navigation.

@zabojad
Copy link

zabojad commented Aug 14, 2018

Hey there! I just would like to revive this PR as it represents some very nice enhancement to the library... Is there any chance we'll get something merged soon :)?

@kLabz
Copy link
Contributor

kLabz commented Aug 14, 2018

Not sure, there's some small issues (code style, breaking changes needing a major version bump, conflict, some details)

I am maintaining a temporary fork of haxe-react with this PR (and an attempt at code style fix) and some other changes here (docs).

@back2dos
Copy link
Author

I'll go ahead and close this to keep my backlog small. It's on react-next and if the two projects are ever merged, I suppose that will also render this PR obsolete ;)

@back2dos back2dos closed this Jun 11, 2020
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants