@@ -1070,6 +1070,34 @@ and expression_desc cxt ~(level : int) f x : cxt =
1070
1070
P. string f " ..." ;
1071
1071
expression ~level: 13 cxt f e)
1072
1072
1073
+ and print_indented_list (f : P.t ) (parent_expr_level : int ) (cxt : cxt )
1074
+ (items : 'a list ) (print_item_func : int -> cxt -> P.t -> 'a -> cxt ) : cxt =
1075
+ if List. length items = 0 then cxt
1076
+ else
1077
+ P. group f 1 (fun () ->
1078
+ (* Increment indent level by 1 for this block of items *)
1079
+ P. newline f;
1080
+ (* Start the block on a new, fully indented line for the first item *)
1081
+ let rec process_items current_cxt_for_fold remaining_items =
1082
+ match remaining_items with
1083
+ | [] ->
1084
+ current_cxt_for_fold
1085
+ (* Base case for recursion, though initial check avoids empty items *)
1086
+ | [last_item] ->
1087
+ (* Print the last item, but DO NOT print a newline after it *)
1088
+ print_item_func parent_expr_level current_cxt_for_fold f last_item
1089
+ | current_item :: next_items ->
1090
+ let cxt_after_current =
1091
+ print_item_func parent_expr_level current_cxt_for_fold f
1092
+ current_item
1093
+ in
1094
+ P. newline f;
1095
+ (* Add a newline AFTER the current item, to prepare for the NEXT item *)
1096
+ process_items cxt_after_current next_items
1097
+ in
1098
+ (* Initial call to the recursive helper; initial check ensures items is not empty *)
1099
+ process_items cxt items)
1100
+
1073
1101
and print_jsx cxt ?(spread_props : J.expression option )
1074
1102
?(key : J.expression option ) ~(level : int ) f (fnName : string )
1075
1103
(tag : J.expression ) (fields : (string * J.expression) list ) : cxt =
@@ -1098,71 +1126,116 @@ and print_jsx cxt ?(spread_props : J.expression option)
1098
1126
else None )
1099
1127
fields
1100
1128
in
1101
- let print_props cxt =
1129
+ let print_props cxt props =
1102
1130
(* If a key is present, should be printed before the spread props,
1103
1131
This is to ensure tools like ESBuild use the automatic JSX runtime *)
1104
- let cxt =
1105
- match key with
1106
- | None -> cxt
1107
- | Some key ->
1108
- P. string f " key={" ;
1109
- let cxt = expression ~level: 0 cxt f key in
1110
- P. string f " } " ;
1111
- cxt
1132
+ let print_key key cxt =
1133
+ P. string f " key={" ;
1134
+ let cxt_k = expression ~level: 0 cxt f key in
1135
+ P. string f " } " ;
1136
+ cxt_k
1112
1137
in
1113
- let props = List. filter (fun (n , _ ) -> n <> " children" ) fields in
1114
- let cxt =
1115
- match spread_props with
1116
- | None -> cxt
1117
- | Some spread ->
1118
- P. string f " {..." ;
1119
- let cxt = expression ~level: 0 cxt f spread in
1120
- P. string f " } " ;
1121
- cxt
1138
+
1139
+ let print_spread_props spread cxt =
1140
+ P. string f " {..." ;
1141
+ let cxt = expression ~level: 0 cxt f spread in
1142
+ P. string f " } " ;
1143
+ cxt
1144
+ in
1145
+
1146
+ let print_prop n x ctx =
1147
+ let prop_name = Js_dump_property. property_key_string n in
1148
+ P. string f prop_name;
1149
+ P. string f " =" ;
1150
+ P. string f " {" ;
1151
+ let next_cxt = expression ~level: 0 ctx f x in
1152
+ P. string f " }" ;
1153
+ next_cxt
1122
1154
in
1123
- if List. length props = 0 then cxt
1155
+ let printable_props =
1156
+ (match key with
1157
+ | None -> []
1158
+ | Some k -> [print_key k])
1159
+ @ (match spread_props with
1160
+ | None -> []
1161
+ | Some spread -> [print_spread_props spread])
1162
+ @ List. map (fun (n , x ) -> print_prop n x) props
1163
+ in
1164
+ if List. length printable_props = 0 then (
1165
+ match children_opt with
1166
+ | Some _ -> cxt
1167
+ | None ->
1168
+ (* Put a space the tag name and /> *)
1169
+ P. space f;
1170
+ cxt)
1124
1171
else
1125
- (List. fold_left (fun acc (n , x ) ->
1126
- P. space f;
1127
- let prop_name = Js_dump_property. property_key_string n in
1128
-
1129
- P. string f prop_name;
1130
- P. string f " =" ;
1131
- P. string f " {" ;
1132
- let next = expression ~level: 0 acc f x in
1133
- P. string f " }" ;
1134
- next))
1135
- cxt props
1172
+ P. group f 1 (fun () ->
1173
+ P. newline f;
1174
+ let rec process_remaining_props acc_cxt printable_props =
1175
+ match printable_props with
1176
+ | [] -> acc_cxt
1177
+ | print_prop :: [] -> print_prop acc_cxt
1178
+ | print_prop :: tail ->
1179
+ let next_cxt = print_prop acc_cxt in
1180
+ P. newline f;
1181
+ process_remaining_props next_cxt tail
1182
+ in
1183
+ process_remaining_props cxt printable_props)
1136
1184
in
1137
- match children_opt with
1138
- | None ->
1139
- P. string f " <" ;
1140
- let cxt = cxt |> print_tag |> print_props in
1141
- P. string f " />" ;
1142
- cxt
1143
- | Some children ->
1144
- let child_is_jsx child =
1145
- match child.J. expression_desc with
1185
+
1186
+ let print_one_child expr_level_for_child current_cxt_for_child f_format
1187
+ child_expr =
1188
+ let child_is_jsx_itself =
1189
+ match child_expr.J. expression_desc with
1146
1190
| J. Call (_ , _ , {call_transformed_jsx = is_jsx } ) -> is_jsx
1147
1191
| _ -> false
1148
1192
in
1193
+ if not child_is_jsx_itself then P. string f_format " {" ;
1194
+ let next_cxt =
1195
+ expression ~level: expr_level_for_child current_cxt_for_child f_format
1196
+ child_expr
1197
+ in
1198
+ if not child_is_jsx_itself then P. string f_format " }" ;
1199
+ next_cxt
1200
+ in
1201
+
1202
+ let props = List. filter (fun (n , _ ) -> n <> " children" ) fields in
1203
+
1204
+ (* Actual printing of JSX element starts here *)
1205
+ P. string f " <" ;
1206
+ let cxt = print_tag cxt in
1207
+ let cxt = print_props cxt props in
1208
+ (* print_props handles its own block and updates cxt *)
1149
1209
1150
- P. string f " <" ;
1151
- let cxt = cxt |> print_tag |> print_props in
1210
+ let has_multiple_props = List. length props > 0 in
1152
1211
1212
+ match children_opt with
1213
+ | None ->
1214
+ (* Self-closing tag *)
1215
+ if has_multiple_props then P. newline f;
1216
+ P. string f " />" ;
1217
+ cxt
1218
+ | Some children ->
1219
+ (* Tag with children *)
1220
+ let has_children = List. length children > 0 in
1221
+ (* Newline for ">" only if props themselves were multi-line. Children alone don't push ">" to a new line. *)
1222
+ if has_multiple_props then P. newline f;
1153
1223
P. string f " >" ;
1154
- if List. length children > 0 then P. newline f;
1155
1224
1156
- let cxt =
1157
- List. fold_left
1158
- (fun acc e ->
1159
- if not (child_is_jsx e) then P. string f " {" ;
1160
- let next = expression ~level acc f e in
1161
- if not (child_is_jsx e) then P. string f " }" ;
1162
- P. newline f;
1163
- next)
1164
- cxt children
1225
+ let cxt_after_children =
1226
+ if has_children then
1227
+ (* Only call print_indented_list if there are children *)
1228
+ print_indented_list f level cxt children print_one_child
1229
+ else cxt
1230
+ (* No children, no change to context here, no newlines from children block *)
1165
1231
in
1232
+ let cxt = cxt_after_children in
1233
+
1234
+ (* The closing "</tag>" goes on a new line if the opening part was multi-line (due to props)
1235
+ OR if there were actual children printed (which always makes the element multi-line).
1236
+ *)
1237
+ let element_content_was_multiline = has_multiple_props || has_children in
1238
+ if element_content_was_multiline then P. newline f;
1166
1239
1167
1240
P. string f " </" ;
1168
1241
let cxt = print_tag cxt in
0 commit comments