Skip to content

Fix React.forwardRef parameter handling in JSX v4 transformation #7778

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions compiler/syntax/src/jsx_v4.ml
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,8 @@ let rec recursively_transform_named_args_for_make expr args newtypes core_type =
| {ppat_desc = Ppat_constraint (_, type_)} -> Some type_
| _ -> None
in
(* The ref arguement of forwardRef should be optional *)
( ( Optional {txt = "ref"; loc = Location.none},
(* The ref argument of forwardRef should be a positional argument, not optional *)
( ( Nolabel,
None,
pattern,
txt,
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
type fn = (@as("something") ~foo: string) => int
./scripts/test_syntax.sh: line 48: /home/runner/work/rescript/rescript/res_parser: No such file or directory
52 changes: 1 addition & 51 deletions tests/syntax_tests/data/ast-mapping/expected/JSXElements.res.txt
Original file line number Diff line number Diff line change
@@ -1,51 +1 @@
let emptyUnary = ReactDOM.jsx("input", {})

let emptyNonunary = ReactDOM.jsx("div", {})

let emptyUnaryWithAttributes = ReactDOM.jsx(
"input",
{
type_: "text",
},
)

let emptyNonunaryWithAttributes = ReactDOM.jsx(
"div",
{
className: "container",
},
)

let elementWithChildren = ReactDOM.jsxs(
"div",
{
children: React.array([
ReactDOM.jsx("h1", {children: ?ReactDOM.someElement({React.string("Hi")})}),
ReactDOM.jsx("p", {children: ?ReactDOM.someElement({React.string("Hello")})}),
]),
},
)

let elementWithChildrenAndAttributes = ReactDOM.jsxs(
"div",
{
className: "container",
children: React.array([
ReactDOM.jsx("h1", {children: ?ReactDOM.someElement({React.string("Hi")})}),
ReactDOM.jsx("p", {children: ?ReactDOM.someElement({React.string("Hello")})}),
]),
},
)

let elementWithConditionalChildren = ReactDOM.jsx(
"div",
{
children: ?ReactDOM.someElement({
if true {
ReactDOM.jsx("h1", {children: ?ReactDOM.someElement({React.string("Hi")})})
} else {
React.null
}
}),
},
)
./scripts/test_syntax.sh: line 48: /home/runner/work/rescript/rescript/res_parser: No such file or directory
Original file line number Diff line number Diff line change
@@ -1,24 +1 @@
let empty = React.jsx(React.jsxFragment, {})

let fragmentWithBracedExpresssion = React.jsx(React.jsxFragment, {children: {React.int(1 + 2)}})

let fragmentWithJSXElements = React.jsxs(
React.jsxFragment,
{
children: React.array([
ReactDOM.jsx("h1", {children: ?ReactDOM.someElement({React.string("Hi")})}),
ReactDOM.jsx("p", {children: ?ReactDOM.someElement({React.string("Hello")})}),
]),
},
)

let nestedFragments = React.jsxs(
React.jsxFragment,
{
children: React.array([
ReactDOM.jsx("h1", {children: ?ReactDOM.someElement({React.string("Hi")})}),
ReactDOM.jsx("p", {children: ?ReactDOM.someElement({React.string("Hello")})}),
React.jsx(React.jsxFragment, {children: {React.string("Bye")}}),
]),
},
)
./scripts/test_syntax.sh: line 48: /home/runner/work/rescript/rescript/res_parser: No such file or directory
Original file line number Diff line number Diff line change
@@ -1,20 +1 @@
module Color: {
type t = private string

@inline("red") let red: t
@inline("black") let black: t
} = {
type t = string

@inline let red = "red"
@inline let black = "black"
}

@send external map: (array<'a>, 'a => 'b) => array<'b> = "map"
@send external filter: (array<'a>, 'a => 'b) => array<'b> = "filter"
list{1, 2, 3}->map(a => a + 1)->filter(a => modulo(a, 2) == 0)->Js.log

type t
@new external make: unit => t = "DOMParser"

Js.log(make()->parseHtmlFromString("sdsd"))
./scripts/test_syntax.sh: line 42: /home/runner/work/rescript/rescript/res_parser: No such file or directory
148 changes: 1 addition & 147 deletions tests/syntax_tests/data/conversion/reason/expected/bracedJsx.res.txt
Original file line number Diff line number Diff line change
@@ -1,147 +1 @@
open Belt

type action =
| RunCommand
| SetValue(string)

type line =
| User(string)
| System(string)

type state = {
history: array<line>,
input: string,
}

module Styles = {
open Css
let terminal = style(list{
margin(10->px),
backgroundColor("222"->hex),
borderRadius(10->px),
padding(10->px),
color("fff"->hex),
height(300->px),
overflowY(auto),
fontFamily(#custom(Theme.codeFontFamily)),
unsafe("WebkitOverflowScrolling", "touch"),
})
let line = style(list{whiteSpace(#preWrap)})
let input = style(list{
backgroundColor("222"->hex),
fontFamily(#custom(Theme.codeFontFamily)),
color("fff"->hex),
fontSize(16->px),
borderWidth(zero),
margin(zero),
padding(zero),
outlineStyle(none),
})
let title = style(list{
fontSize(48->px),
fontWeight(extraBold),
marginTop(20->px),
marginBottom(20->px),
textAlign(center),
})
}

@react.component
let make = () => {
let containerRef = React.useRef(Js.Nullable.null)

let (state, send) = React.useReducer((state, action) =>
switch action {
| RunCommand => {
input: "",
history: Array.concat(
state.history,
[
User(state.input),
switch state.input->Js.String.trim {
| "" => System("")
| "help" =>
System(`available commands:
- help
- ls
- cat `)
| "ls" =>
System(`- hack-website.sh
- go-to-home.sh
- nuclear-codes.txt`)
| "cat" => System("cat: missing argument")
| "cat hack-website.sh"
| "cat ./hack-website.sh" =>
System("# seriously?\necho \"lol\"")
| "hack-website.sh"
| "./hack-website.sh" =>
System("lol")
| "cat nuclear-codes.txt"
| "cat ./nuclear-codes.txt" =>
System("000000")
| "go-to-home.sh"
| "./go-to-home.sh" =>
Js.Global.setTimeout(() => ReasonReact.Router.push("/"), 1_000)->ignore
System("Redirecting ...")
| "cat go-to-home.sh"
| "cat ./go-to-home.sh" =>
System("ReasonReact.Router.push(\"/\")")
| _ => System("command not found: " ++ (state.input ++ "\ntry command 'help'"))
},
],
),
}
| SetValue(input) => {...state, input}
}
, {history: [], input: ""})

React.useEffect1(() => {
switch containerRef.current->Js.Nullable.toOption {
| Some(containerRef) =>
open Webapi.Dom
containerRef->Element.setScrollTop(containerRef->Element.scrollHeight->float_of_int)
| None => ()
}
None
}, [state.history])

let userPrefix = "~ "
<WidthContainer>
<div role="heading" ariaLevel=1 className=Styles.title> {"Erreur"->ReasonReact.string} </div>
<div
className=Styles.terminal
onClick={event => (event->ReactEvent.Mouse.target)["querySelector"]("input")["focus"]()}
ref={containerRef->ReactDOMRe.Ref.domRef}>
{state.history
->Array.mapWithIndex((index, item) =>
<div key={j`$index`} className=Styles.line>
{ReasonReact.string(
switch item {
| User(value) => userPrefix ++ value
| System(value) => value
},
)}
</div>
)
->ReasonReact.array}
<div>
{userPrefix->ReasonReact.string}
{<input
type_="text"
className=Styles.input
autoFocus=true
value=state.input
onChange={event => send(SetValue((event->ReactEvent.Form.target)["value"]))}
onKeyDown={event => {
if event->ReactEvent.Keyboard.key == "Enter" {
send(RunCommand)
}
if event->ReactEvent.Keyboard.key == "Tab" {
event->ReactEvent.Keyboard.preventDefault
}
}}
/>->ReasonReact.cloneElement(~props={"autoCapitalize": "off"}, [])}
</div>
</div>
</WidthContainer>
}
./scripts/test_syntax.sh: line 42: /home/runner/work/rescript/rescript/res_parser: No such file or directory
Original file line number Diff line number Diff line change
@@ -1,24 +1 @@
let f = () => id
let f = () => id

if isArray(children) {
// Scenario 1
let code = children->asStringArray->Js.Array2.joinWith("")
<InlineCode> {code->s} </InlineCode>
} else if isObject(children) {
// Scenario 2
children->asElement
} else {
// Scenario 3
let code = unknownAsString(children)
makeCodeElement(~code, ~metastring, ~lang)
}

let getDailyNewCases = x =>
switch x {
| First(ret) => ret
| Pair({prevRecord, record}) =>
let confirmed = record.confirmed - prevRecord.confirmed
let deaths = record.deaths - prevRecord.deaths
{confirmed, deaths}
}
./scripts/test_syntax.sh: line 42: /home/runner/work/rescript/rescript/res_parser: No such file or directory
Loading