@@ -1053,7 +1053,7 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
1053
1053
~kind: (Completion. Value (Ctype. newty (Ttuple typeExrps)));
1054
1054
]
1055
1055
else []
1056
- | CJsxPropValue {pathToComponent; propName} -> (
1056
+ | CJsxPropValue {pathToComponent; propName; emptyJsxPropNameHint } -> (
1057
1057
if Debug. verbose () then print_endline " [ctx_path]--> CJsxPropValue" ;
1058
1058
let findTypeOfValue path =
1059
1059
path
@@ -1067,7 +1067,7 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
1067
1067
| _ -> false
1068
1068
in
1069
1069
(* TODO(env-stuff) Does this need to potentially be instantiated with type args too? *)
1070
- let targetLabel =
1070
+ let labels =
1071
1071
if lowercaseComponent then
1072
1072
let rec digToTypeForCompletion path =
1073
1073
match
@@ -1081,17 +1081,39 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
1081
1081
ReactDOM.domProps is an alias for JsxEvent.t. *)
1082
1082
let pathRev = p |> Utils. expandPath in
1083
1083
pathRev |> List. rev |> digToTypeForCompletion
1084
- | {kind = Type {kind = Record fields } } :: _ -> (
1085
- match fields |> List. find_opt (fun f -> f.fname.txt = propName) with
1086
- | None -> None
1087
- | Some f -> Some (f.fname.txt, f.typ, env))
1088
- | _ -> None
1084
+ | {kind = Type {kind = Record fields } } :: _ ->
1085
+ fields |> List. map (fun f -> (f.fname.txt, f.typ, env))
1086
+ | _ -> []
1089
1087
in
1090
1088
TypeUtils. pathToElementProps package |> digToTypeForCompletion
1091
1089
else
1092
1090
CompletionJsx. getJsxLabels ~component Path:pathToComponent
1093
1091
~find TypeOfValue ~package
1094
- |> List. find_opt (fun (label , _ , _ ) -> label = propName)
1092
+ in
1093
+ (* We have a heuristic that kicks in when completing empty prop expressions in the middle of a JSX element,
1094
+ like <SomeComp firstProp=test second=<com> third=123 />.
1095
+ The parser turns that broken JSX into: <SomeComp firstProp=test second=<com>third />, 123.
1096
+
1097
+ So, we use a heuristic that covers this scenario by picking up on the cursor being between
1098
+ the prop name and the prop expression, and the prop expression being an ident that's a
1099
+ _valid prop name_ for that JSX element.
1100
+
1101
+ This works because the ident itself will always be the next prop name (since that's what the
1102
+ parser eats). So, we do a simple lookup of that hint here if it exists, to make sure the hint
1103
+ is indeed a valid label for this JSX element. *)
1104
+ let emptyJsxPropNameHintIsCorrect =
1105
+ match emptyJsxPropNameHint with
1106
+ | Some identName when identName != propName ->
1107
+ labels
1108
+ |> List. find_opt (fun (f , _ , _ ) -> f = identName)
1109
+ |> Option. is_some
1110
+ | Some _ -> false
1111
+ | None -> true
1112
+ in
1113
+ let targetLabel =
1114
+ if emptyJsxPropNameHintIsCorrect then
1115
+ labels |> List. find_opt (fun (f , _ , _ ) -> f = propName)
1116
+ else None
1095
1117
in
1096
1118
match targetLabel with
1097
1119
| None -> []
0 commit comments