Skip to content

Commit e48b26e

Browse files
committed
adapt the primitive completions inside of jsx to the generic JSX moe
1 parent 26f37f5 commit e48b26e

22 files changed

+383
-155
lines changed

analysis/src/CompletionBackEnd.ml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,14 +1010,23 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
10101010
| Some (builtinNameToComplete, typ)
10111011
when Utils.checkName builtinNameToComplete ~prefix:funNamePrefix
10121012
~exact:false ->
1013+
let name =
1014+
match package.genericJsxModule with
1015+
| None -> "React." ^ builtinNameToComplete
1016+
| Some g ->
1017+
g ^ "." ^ builtinNameToComplete
1018+
|> String.split_on_char '.'
1019+
|> TypeUtils.removeOpensFromCompletionPath ~rawOpens
1020+
~package:full.package
1021+
|> String.concat "."
1022+
in
10131023
[
1014-
Completion.createWithSnippet
1015-
~name:("React." ^ builtinNameToComplete)
1016-
~kind:(Value typ) ~env ~sortText:"A"
1024+
Completion.createWithSnippet ~name ~kind:(Value typ) ~env
1025+
~sortText:"A"
10171026
~docstring:
10181027
[
10191028
"Turns `" ^ builtinNameToComplete
1020-
^ "` into `React.element` so it can be used inside of JSX.";
1029+
^ "` into a JSX element so it can be used inside of JSX.";
10211030
]
10221031
();
10231032
]

analysis/src/CompletionDecorators.ml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,17 @@ Example `@raises(Exn)` or `@raises([E1, E2, E3])` for multiple exceptions.
164164

165165
You will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions.
166166

167-
Note: The `@react.component` decorator requires the react-jsx config to be set in your `bsconfig.json` to enable the required React transformations.
167+
Note: The `@react.component` decorator requires the `jsx` config to be set in your `rescript.json`/`bsconfig.json` to enable the required React transformations.
168168

169169
[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#react-component-decorator).|};
170170
] );
171+
( "jsx.component",
172+
None,
173+
[
174+
{|The `@jsx.component` decorator is used to annotate functions that are JSX components used with ReScript's [generic JSX transform](https://rescript-lang.org/docs/manual/latest/jsx#generic-jsx-transform-jsx-beyond-react-experimental).
175+
176+
You will need this decorator whenever you want to use a JSX component in ReScript JSX expressions.|};
177+
] );
171178
( "return",
172179
Some "return(${1:nullable})",
173180
[

analysis/src/CompletionFrontEnd.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
659659
let value_binding (iterator : Ast_iterator.iterator)
660660
(value_binding : Parsetree.value_binding) =
661661
let oldInJsxContext = !inJsxContext in
662-
if Utils.isReactComponent value_binding then inJsxContext := true;
662+
if Utils.isJsxComponent value_binding then inJsxContext := true;
663663
(match value_binding with
664664
| {pvb_pat = {ppat_desc = Ppat_constraint (_pat, coreType)}; pvb_expr}
665665
when locHasCursor pvb_expr.pexp_loc -> (

analysis/src/TypeUtils.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1083,4 +1083,4 @@ let removeOpensFromCompletionPath ~rawOpens ~package completionPath =
10831083
let pathToElementProps package =
10841084
match package.genericJsxModule with
10851085
| None -> ["ReactDOM"; "domProps"]
1086-
| Some g -> (g |> String.split_on_char '.') @ ["DOM"; "props"]
1086+
| Some g -> (g |> String.split_on_char '.') @ ["Elements"; "props"]

analysis/src/Utils.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,10 @@ let rec unwrapIfOption (t : Types.type_expr) =
156156
| Tconstr (Path.Pident {name = "option"}, [unwrappedType], _) -> unwrappedType
157157
| _ -> t
158158

159-
let isReactComponent (vb : Parsetree.value_binding) =
159+
let isJsxComponent (vb : Parsetree.value_binding) =
160160
vb.pvb_attributes
161161
|> List.exists (function
162-
| {Location.txt = "react.component"}, _payload -> true
162+
| {Location.txt = "react.component" | "jsx.component"}, _payload -> true
163163
| _ -> false)
164164

165165
let checkName name ~prefix ~exact =

analysis/src/Xform.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,9 @@ module AddTypeAnnotation = struct
215215
match si.pstr_desc with
216216
| Pstr_value (_recFlag, bindings) ->
217217
let processBinding (vb : Parsetree.value_binding) =
218-
(* Can't add a type annotation to a react component, or the compiler crashes *)
219-
let isReactComponent = Utils.isReactComponent vb in
220-
if not isReactComponent then processPattern vb.pvb_pat;
218+
(* Can't add a type annotation to a jsx component, or the compiler crashes *)
219+
let isJsxComponent = Utils.isJsxComponent vb in
220+
if not isJsxComponent then processPattern vb.pvb_pat;
221221
processFunction vb.pvb_expr
222222
in
223223
bindings |> List.iter (processBinding ~argNum:1);

analysis/tests-generic-jsx-transform/package-lock.json

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

analysis/tests-generic-jsx-transform/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
},
66
"private": true,
77
"dependencies": {
8-
"rescript": "11.1.0-rc.1"
8+
"rescript": "11.1.0-rc.2"
99
}
1010
}

analysis/tests-generic-jsx-transform/src/GenericJsx.res

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@ type fragmentProps = {children?: element}
3333
@module("preact") external jsxFragment: component<fragmentProps> = "Fragment"
3434

3535
/* The Elements module is the equivalent to the ReactDOM module in React. This holds things relevant to _lowercase_ JSX elements. */
36-
module DOM = {
36+
module Elements = {
3737
/* Here you can control what props lowercase JSX elements should have.
3838
A base that the React JSX transform uses is provided via JsxDOM.domProps,
3939
but you can make this anything. The editor tooling will support
4040
autocompletion etc for your specific type. */
4141
type props = {
42-
testing?: bool,
43-
test2?: string
42+
testing?: bool,
43+
test2?: string,
44+
children?: element
4445
}
4546

4647
@module("preact")
Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
// <div
22
// ^com
33

4-
// <div testing=
5-
// ^com
4+
// <div testing={}
5+
// ^com
6+
7+
module SomeComponent = {
8+
@jsx.component
9+
let make = (~someProp) => {
10+
let someString = ""
11+
let someInt = 12
12+
let someArr = [GenericJsx.null]
13+
ignore(someInt)
14+
ignore(someArr)
15+
// someString->st
16+
// ^com
17+
open GenericJsx
18+
<div>
19+
{GenericJsx.string(someProp)}
20+
<div> {GenericJsx.null} </div>
21+
// {someString->st}
22+
// ^com
23+
</div>
24+
}
25+
}

analysis/tests-generic-jsx-transform/src/expected/GenericJsxCompletion.res.txt

Lines changed: 104 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ JSX <div:[0:4->0:7] > _children:None
44
Completable: Cjsx([div], "", [])
55
Package opens Pervasives.JsxModules.place holder
66
Resolved opens 1 pervasives
7-
Path GenericJsx.DOM.props
7+
Path GenericJsx.Elements.props
88
[{
99
"label": "testing",
1010
"kind": 4,
@@ -17,16 +17,22 @@ Path GenericJsx.DOM.props
1717
"tags": [],
1818
"detail": "string",
1919
"documentation": null
20+
}, {
21+
"label": "children",
22+
"kind": 4,
23+
"tags": [],
24+
"detail": "element",
25+
"documentation": null
2026
}]
2127

22-
Complete src/GenericJsxCompletion.res 3:16
23-
posCursor:[3:16] posNoWhite:[3:15] Found expr:[3:4->3:16]
24-
JSX <div:[3:4->3:7] testing[3:8->3:15]=...__ghost__[0:-1->0:-1]> _children:None
25-
Completable: Cexpression CJsxPropValue [div] testing
28+
Complete src/GenericJsxCompletion.res 3:17
29+
posCursor:[3:17] posNoWhite:[3:16] Found expr:[3:4->3:18]
30+
JSX <div:[3:4->3:7] testing[3:8->3:15]=...[3:16->3:18]> _children:None
31+
Completable: Cexpression CJsxPropValue [div] testing->recordBody
2632
Package opens Pervasives.JsxModules.place holder
2733
Resolved opens 1 pervasives
2834
ContextPath CJsxPropValue [div] testing
29-
Path GenericJsx.DOM.props
35+
Path GenericJsx.Elements.props
3036
[{
3137
"label": "true",
3238
"kind": 4,
@@ -41,3 +47,95 @@ Path GenericJsx.DOM.props
4147
"documentation": null
4248
}]
4349

50+
Complete src/GenericJsxCompletion.res 14:21
51+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[8:13->23:3]
52+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[8:14->23:3]
53+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[9:1->22:10]
54+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[10:4->22:10]
55+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[11:4->22:10]
56+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[12:4->22:10]
57+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[13:4->22:10]
58+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[14:7->22:10]
59+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[14:7->14:21]
60+
Completable: Cpath Value[someString]->st <<jsx>>
61+
Package opens Pervasives.JsxModules.place holder
62+
Resolved opens 1 pervasives
63+
ContextPath Value[someString]->st <<jsx>>
64+
ContextPath Value[someString]
65+
Path someString
66+
CPPipe env:GenericJsxCompletion
67+
Path Js.String2.st
68+
[{
69+
"label": "GenericJsx.string",
70+
"kind": 12,
71+
"tags": [],
72+
"detail": "string",
73+
"documentation": {"kind": "markdown", "value": "Turns `string` into `GenericJsx.element` so it can be used inside of JSX."},
74+
"sortText": "A",
75+
"insertTextFormat": 2
76+
}, {
77+
"label": "Js.String2.startsWith",
78+
"kind": 12,
79+
"tags": [],
80+
"detail": "(t, t) => bool",
81+
"documentation": {"kind": "markdown", "value": "\nES2015: `startsWith(str, substr)` returns `true` if the `str` starts with\n`substr`, `false` otherwise.\n\nSee [`String.startsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith)\non MDN.\n\n## Examples\n\n```rescript\nJs.String2.startsWith(\"ReScript\", \"Re\") == true\nJs.String2.startsWith(\"ReScript\", \"\") == true\nJs.String2.startsWith(\"JavaScript\", \"Re\") == false\n```\n"}
82+
}, {
83+
"label": "Js.String2.startsWithFrom",
84+
"kind": 12,
85+
"tags": [],
86+
"detail": "(t, t, int) => bool",
87+
"documentation": {"kind": "markdown", "value": "\nES2015: `startsWithFrom(str, substr, n)` returns `true` if the `str` starts\nwith `substr` starting at position `n`, false otherwise. If `n` is negative,\nthe search starts at the beginning of `str`.\n\nSee [`String.startsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith)\non MDN.\n\n## Examples\n\n```rescript\nJs.String2.startsWithFrom(\"ReScript\", \"Scri\", 2) == true\nJs.String2.startsWithFrom(\"ReScript\", \"\", 2) == true\nJs.String2.startsWithFrom(\"JavaScript\", \"Scri\", 2) == false\n```\n"}
88+
}]
89+
90+
Complete src/GenericJsxCompletion.res 20:24
91+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[8:13->23:3]
92+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[8:14->23:3]
93+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[9:1->22:10]
94+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[10:4->22:10]
95+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[11:4->22:10]
96+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[12:4->22:10]
97+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[13:4->22:10]
98+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[16:1->22:10]
99+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[17:5->22:10]
100+
JSX <div:[17:5->17:8] > _children:17:8
101+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[17:8->22:4]
102+
Pexp_construct :::[18:7->22:4] [18:7->22:4]
103+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[18:7->22:4]
104+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[19:7->22:4]
105+
Pexp_construct :::[19:7->22:4] [19:7->22:4]
106+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[19:7->22:4]
107+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[20:10->22:4]
108+
Pexp_construct :::[20:10->22:4] [20:10->22:4]
109+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[20:10->22:4]
110+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[20:10->20:24]
111+
Completable: Cpath Value[someString]->st <<jsx>>
112+
Raw opens: 1 GenericJsx.place holder
113+
Package opens Pervasives.JsxModules.place holder
114+
Resolved opens 2 pervasives GenericJsx.res
115+
ContextPath Value[someString]->st <<jsx>>
116+
ContextPath Value[someString]
117+
Path someString
118+
CPPipe env:GenericJsxCompletion
119+
Path Js.String2.st
120+
[{
121+
"label": "string",
122+
"kind": 12,
123+
"tags": [],
124+
"detail": "string",
125+
"documentation": {"kind": "markdown", "value": "Turns `string` into `GenericJsx.element` so it can be used inside of JSX."},
126+
"sortText": "A",
127+
"insertTextFormat": 2
128+
}, {
129+
"label": "Js.String2.startsWith",
130+
"kind": 12,
131+
"tags": [],
132+
"detail": "(t, t) => bool",
133+
"documentation": {"kind": "markdown", "value": "\nES2015: `startsWith(str, substr)` returns `true` if the `str` starts with\n`substr`, `false` otherwise.\n\nSee [`String.startsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith)\non MDN.\n\n## Examples\n\n```rescript\nJs.String2.startsWith(\"ReScript\", \"Re\") == true\nJs.String2.startsWith(\"ReScript\", \"\") == true\nJs.String2.startsWith(\"JavaScript\", \"Re\") == false\n```\n"}
134+
}, {
135+
"label": "Js.String2.startsWithFrom",
136+
"kind": 12,
137+
"tags": [],
138+
"detail": "(t, t, int) => bool",
139+
"documentation": {"kind": "markdown", "value": "\nES2015: `startsWithFrom(str, substr, n)` returns `true` if the `str` starts\nwith `substr` starting at position `n`, false otherwise. If `n` is negative,\nthe search starts at the beginning of `str`.\n\nSee [`String.startsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith)\non MDN.\n\n## Examples\n\n```rescript\nJs.String2.startsWithFrom(\"ReScript\", \"Scri\", 2) == true\nJs.String2.startsWithFrom(\"ReScript\", \"\", 2) == true\nJs.String2.startsWithFrom(\"JavaScript\", \"Scri\", 2) == false\n```\n"}
140+
}]
141+

analysis/tests/package-lock.json

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

analysis/tests/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
"@rescript/react": "0.12.0"
99
},
1010
"dependencies": {
11-
"rescript": "11.0.1"
11+
"rescript": "11.1.0-rc.2"
1212
}
1313
}

analysis/tests/src/expected/Completion.res.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ Resolved opens 1 pervasives
553553
"kind": 4,
554554
"tags": [],
555555
"detail": "",
556-
"documentation": {"kind": "markdown", "value": "The `@react.component` decorator is used to annotate functions that are RescriptReact components.\n\nYou will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions.\n\nNote: The `@react.component` decorator requires the react-jsx config to be set in your `bsconfig.json` to enable the required React transformations.\n\n[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#react-component-decorator)."},
556+
"documentation": {"kind": "markdown", "value": "The `@react.component` decorator is used to annotate functions that are RescriptReact components.\n\nYou will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions.\n\nNote: The `@react.component` decorator requires the `jsx` config to be set in your `rescript.json`/`bsconfig.json` to enable the required React transformations.\n\n[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#react-component-decorator)."},
557557
"insertTextFormat": 2
558558
}]
559559

@@ -569,7 +569,7 @@ Resolved opens 1 pervasives
569569
"kind": 4,
570570
"tags": [],
571571
"detail": "",
572-
"documentation": {"kind": "markdown", "value": "The `@react.component` decorator is used to annotate functions that are RescriptReact components.\n\nYou will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions.\n\nNote: The `@react.component` decorator requires the react-jsx config to be set in your `bsconfig.json` to enable the required React transformations.\n\n[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#react-component-decorator)."},
572+
"documentation": {"kind": "markdown", "value": "The `@react.component` decorator is used to annotate functions that are RescriptReact components.\n\nYou will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions.\n\nNote: The `@react.component` decorator requires the `jsx` config to be set in your `rescript.json`/`bsconfig.json` to enable the required React transformations.\n\n[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#react-component-decorator)."},
573573
"insertTextFormat": 2
574574
}]
575575

analysis/tests/src/expected/CompletionJsx.res.txt

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -429,17 +429,17 @@ posCursor:[30:12] posNoWhite:[30:11] Found expr:[11:4->32:10]
429429
posCursor:[30:12] posNoWhite:[30:11] Found expr:[12:4->32:10]
430430
posCursor:[30:12] posNoWhite:[30:11] Found expr:[15:5->32:10]
431431
JSX <div:[15:5->15:8] > _children:15:8
432-
posCursor:[30:12] posNoWhite:[30:11] Found expr:[15:8->32:4]
433-
Pexp_construct :::[16:7->32:4] [16:7->32:4]
434-
posCursor:[30:12] posNoWhite:[30:11] Found expr:[16:7->32:4]
435-
posCursor:[30:12] posNoWhite:[30:11] Found expr:[17:7->32:4]
436-
Pexp_construct :::[17:7->32:4] [17:7->32:4]
437-
posCursor:[30:12] posNoWhite:[30:11] Found expr:[17:7->32:4]
438-
posCursor:[30:12] posNoWhite:[30:11] Found expr:[30:10->32:4]
439-
Pexp_construct :::[30:10->32:4] [30:10->32:4]
440-
posCursor:[30:12] posNoWhite:[30:11] Found expr:[30:10->32:4]
441-
posCursor:[30:12] posNoWhite:[30:11] Found expr:[30:10->30:12]
442-
JSX <di:[30:10->30:12] > _children:None
432+
posCursor:[30:12] posNoWhite:[30:11] Found expr:[15:8->33:2]
433+
Pexp_construct :::[16:7->33:2] [16:7->33:2]
434+
posCursor:[30:12] posNoWhite:[30:11] Found expr:[16:7->33:2]
435+
posCursor:[30:12] posNoWhite:[30:11] Found expr:[17:7->33:2]
436+
Pexp_construct :::[17:7->33:2] [17:7->33:2]
437+
posCursor:[30:12] posNoWhite:[30:11] Found expr:[17:7->33:2]
438+
posCursor:[30:12] posNoWhite:[30:11] Found expr:[30:10->33:2]
439+
Pexp_construct :::[30:10->33:2] [30:10->33:2]
440+
posCursor:[30:12] posNoWhite:[30:11] Found expr:[30:10->33:2]
441+
posCursor:[30:12] posNoWhite:[30:11] Found expr:[30:10->32:10]
442+
JSX <di:[30:10->30:12] div[32:6->32:9]=...[32:6->32:9]> _children:32:9
443443
Completable: ChtmlElement <di
444444
Package opens Pervasives.JsxModules.place holder
445445
Resolved opens 1 pervasives

0 commit comments

Comments
 (0)