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

Jsx parsing error where using hyphen prop name #6723

Open
mununki opened this issue Apr 15, 2024 · 8 comments
Open

Jsx parsing error where using hyphen prop name #6723

mununki opened this issue Apr 15, 2024 · 8 comments

Comments

@mununki
Copy link
Member

mununki commented Apr 15, 2024

I've tried to use a custom data attribute for lower case jsx.

module Div = {
  type props = {
    ...JsxDOM.domProps,
    \"data-a": string,
  }
  @module("react/jsx-runtime")
  external jsx: (string, props) => Jsx.element = "jsx"

  let make = (props: props) => jsx("div", props)
}

let customDiv = <Div name="div" data-a="a" />
FAILED: src/Abstract.ast

  Syntax error!
  /Users/woonki/GitHub/projects/rescript-test/src/Abstract.res:82:37

  80 │ }
  81 │ 
  82 │ let customDiv = <Div name="div" data-a="a" />
  83 │ 

  I'm not sure what to parse here when looking at "-".

There are two workaround here.

  1. If I replace the name props after data-a, the build is fine. <Div data-a="a" name="div" />
  2. If I don't format the code and keep the prop being exotic, then the build is fine. <Div name="div" \"data-a"="a" />
@mununki
Copy link
Member Author

mununki commented Apr 15, 2024

@tsnobip I guess this change may be related #6705

@tsnobip
Copy link
Contributor

tsnobip commented Apr 15, 2024

this works, so I guess it's just again a wrong handling of the jsx mode in the parser.

let customDiv = <Div data-a="a" />

@mununki
Copy link
Member Author

mununki commented Apr 15, 2024

this works, so I guess it's just again a wrong handling of the jsx mode in the parser.

let customDiv = <Div data-a="a" />

Indeed, actually I'm working on the * mode in parser, so I'll take a look to fix it.

@mununki
Copy link
Member Author

mununki commented Apr 15, 2024

Looking at the parser to remove the mode state, I think I understand the underlying reason why we needed a mode list ref type state value. I think it's because the parse* functions all call Parser.next at the end, and why that's a problem is because it affects the parsing of the next token at an earlier, unrelated stage.

For example, parsing props, name="n" data-a="a", will call Parser.next (strictly unsafeNext) at the end of the parseConstant function that parses "n", which means that the function that parses "n" will need to make a decision about parsing the next token, data-a. I don't think parseConstant should be deciding how to parse data-a, so why do we do Parser.next at the end of the parse* function, because we want to see the next Parser.token value immediately after the parse* function call. I think the current implementation makes it necessary to have a mode state outside of the parse* function to toggle it on and off.

Specifically, to parse the above props correctly without the mode state, we need to do this

let parseConstant ?(jsx_mode=false) p ... =
  ...
  Parser.next ~jsx_mode

let parseJsxProps p ...
  ...
  parseConstant ~jsx_mode:true p  (* parseConstant should not affect next ident for props *)
  ...

So what I would suggest is to change the implementation so that the parse* function does not call Parser.next at the end for the next operation, but peeks, consumes and returns the expression.

@tsnobip Can I have your thoughts about it?

@mununki
Copy link
Member Author

mununki commented Apr 15, 2024

That is why this issue happens:

<div data-a="a" /> // fine
<div name="n" data-a="a" /> // syntax error

@tsnobip
Copy link
Contributor

tsnobip commented Apr 15, 2024

So what I would suggest is to change the implementation so that the parse* function does not call Parser.next at the end for the next operation, but peeks, consumes and returns the expression.

Definitely, I had the same realization, right now modes necessarily "leak" before switching, there are a few util functions that try to mitigate this by retrying the token, but it definitely feels suboptimal!

@predragnikolic
Copy link

Related,

https://rescript-lang.org/docs/manual/latest/jsx#hyphens-in-tag-names

Note though that props names can't have hyphens, you should use @as to bind to such props in your custom JsxDOM.domProps type (see generic JSX transform).

@tsnobip
Copy link
Contributor

tsnobip commented Apr 16, 2024

Related,

https://rescript-lang.org/docs/manual/latest/jsx#hyphens-in-tag-names

Note though that props names can't have hyphens, you should use @as to bind to such props in your custom JsxDOM.domProps type (see generic JSX transform).

Yes @predragnikolic, using @as is still the recommended way to bind to props with hyphens. The issue is actually a bit more generic about the reliability of the parser.

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

No branches or pull requests

3 participants