@@ -108,17 +108,22 @@ impl FormatJsxChildList {
108
108
) ,
109
109
} ) ,
110
110
111
- _ => None ,
111
+ Some ( JsxChild :: Newline | JsxChild :: Whitespace | JsxChild :: EmptyLine ) => {
112
+ None
113
+ }
114
+
115
+ None => None ,
112
116
} ;
113
117
114
118
child_breaks = separator. map_or ( false , |separator| separator. will_break ( ) ) ;
115
119
116
120
flat. write ( & format_args ! [ word, separator] , f) ;
117
121
118
122
if let Some ( separator) = separator {
119
- multiline. write ( word, & separator, f) ;
123
+ multiline. write_with_separator ( word, & separator, f) ;
120
124
} else {
121
- multiline. write_with_empty_separator ( word, f) ;
125
+ // it's safe to write without a separator because None means that next element is a separator or end of the iterator
126
+ multiline. write_content ( word, f) ;
122
127
}
123
128
}
124
129
@@ -139,7 +144,7 @@ impl FormatJsxChildList {
139
144
let is_trailing_or_only_whitespace = children_iter. peek ( ) . is_none ( ) ;
140
145
141
146
if is_trailing_or_only_whitespace || is_after_line_break {
142
- multiline. write_with_empty_separator ( & JsxRawSpace , f) ;
147
+ multiline. write_separator ( & JsxRawSpace , f) ;
143
148
}
144
149
// Leading whitespace. Only possible if used together with a expression child
145
150
//
@@ -151,30 +156,30 @@ impl FormatJsxChildList {
151
156
// </div>
152
157
// ```
153
158
else if last. is_none ( ) {
154
- multiline. write ( & JsxRawSpace , & hard_line_break ( ) , f) ;
159
+ multiline. write_with_separator ( & JsxRawSpace , & hard_line_break ( ) , f) ;
155
160
} else {
156
- multiline. write_with_empty_separator ( & JsxSpace , f) ;
161
+ multiline. write_separator ( & JsxSpace , f) ;
157
162
}
158
163
}
159
164
160
165
// A new line between some JSX text and an element
161
166
JsxChild :: Newline => {
162
167
child_breaks = true ;
163
168
164
- multiline. write_with_empty_separator ( & hard_line_break ( ) , f) ;
169
+ multiline. write_separator ( & hard_line_break ( ) , f) ;
165
170
}
166
171
167
172
// An empty line between some JSX text and an element
168
173
JsxChild :: EmptyLine => {
169
174
child_breaks = true ;
170
175
171
- multiline. write_with_empty_separator ( & empty_line ( ) , f) ;
176
+ multiline. write_separator ( & empty_line ( ) , f) ;
172
177
}
173
178
174
179
// Any child that isn't text
175
180
JsxChild :: NonText ( non_text) => {
176
181
let line_mode = match children_iter. peek ( ) {
177
- Some ( JsxChild :: Newline | JsxChild :: Word ( _ ) | JsxChild :: Whitespace ) => {
182
+ Some ( JsxChild :: Word ( word ) ) => {
178
183
// Break if the current or next element is a self closing element
179
184
// ```javascript
180
185
// <pre className="h-screen overflow-y-scroll" />adefg
@@ -184,36 +189,54 @@ impl FormatJsxChildList {
184
189
// <pre className="h-screen overflow-y-scroll" />
185
190
// adefg
186
191
// ```
187
- if matches ! ( non_text, JsxAnyChild :: JsxSelfClosingElement ( _) ) {
192
+ if matches ! ( non_text, JsxAnyChild :: JsxSelfClosingElement ( _) )
193
+ && !word. is_ascii_punctuation ( )
194
+ {
188
195
Some ( LineMode :: Hard )
189
196
} else {
190
197
Some ( LineMode :: Soft )
191
198
}
192
199
}
193
200
194
201
// Add a hard line break if what comes after the element is not a text or is all whitespace
195
- Some ( _ ) => Some ( LineMode :: Hard ) ,
202
+ Some ( JsxChild :: NonText ( _ ) ) => Some ( LineMode :: Hard ) ,
196
203
204
+ Some ( JsxChild :: Newline | JsxChild :: Whitespace | JsxChild :: EmptyLine ) => {
205
+ None
206
+ }
197
207
// Don't insert trailing line breaks
198
208
None => None ,
199
209
} ;
200
210
201
211
child_breaks = line_mode. map_or ( false , |mode| mode. is_hard ( ) ) ;
202
212
203
- let format_separator = format_with ( |f| match line_mode {
204
- Some ( mode) => f. write_element ( FormatElement :: Line ( mode) ) ,
205
- None => Ok ( ( ) ) ,
213
+ let format_separator = line_mode. map ( |mode| {
214
+ format_with ( move |f| f. write_element ( FormatElement :: Line ( mode) ) )
206
215
} ) ;
207
216
208
217
if force_multiline {
209
- multiline. write ( & non_text. format ( ) , & format_separator, f) ;
218
+ if let Some ( format_separator) = format_separator {
219
+ multiline. write_with_separator (
220
+ & non_text. format ( ) ,
221
+ & format_separator,
222
+ f,
223
+ ) ;
224
+ } else {
225
+ // it's safe to write without a separator because None means that next element is a separator or end of the iterator
226
+ multiline. write_content ( & non_text. format ( ) , f) ;
227
+ }
210
228
} else {
211
229
let mut memoized = non_text. format ( ) . memoized ( ) ;
212
230
213
231
force_multiline = memoized. inspect ( f) ?. will_break ( ) ;
214
-
215
232
flat. write ( & format_args ! [ memoized, format_separator] , f) ;
216
- multiline. write ( & memoized, & format_separator, f) ;
233
+
234
+ if let Some ( format_separator) = format_separator {
235
+ multiline. write_with_separator ( & memoized, & format_separator, f) ;
236
+ } else {
237
+ // it's safe to write without a separator because None means that next element is a separator or end of the iterator
238
+ multiline. write_content ( & memoized, f) ;
239
+ }
217
240
}
218
241
}
219
242
}
@@ -476,18 +499,30 @@ impl MultilineBuilder {
476
499
}
477
500
478
501
/// Formats an element that does not require a separator
479
- fn write_with_empty_separator (
502
+ /// It is safe to omit the separator because at the call side we must guarantee that we have reached the end of the iterator
503
+ /// or the next element is a space/newline that should be written into the separator "slot".
504
+ fn write_content ( & mut self , content : & dyn Format < JsFormatContext > , f : & mut JsFormatter ) {
505
+ self . write ( content, None , f) ;
506
+ }
507
+
508
+ /// Formatting a separator does not require any element in the separator slot
509
+ fn write_separator ( & mut self , separator : & dyn Format < JsFormatContext > , f : & mut JsFormatter ) {
510
+ self . write ( separator, None , f) ;
511
+ }
512
+
513
+ fn write_with_separator (
480
514
& mut self ,
481
515
content : & dyn Format < JsFormatContext > ,
516
+ separator : & dyn Format < JsFormatContext > ,
482
517
f : & mut JsFormatter ,
483
518
) {
484
- self . write ( content, & format_with ( |_| Ok ( ( ) ) ) , f)
519
+ self . write ( content, Some ( separator ) , f) ;
485
520
}
486
521
487
522
fn write (
488
523
& mut self ,
489
524
content : & dyn Format < JsFormatContext > ,
490
- separator : & dyn Format < JsFormatContext > ,
525
+ separator : Option < & dyn Format < JsFormatContext > > ,
491
526
f : & mut JsFormatter ,
492
527
) {
493
528
let result = std:: mem:: replace ( & mut self . result , Ok ( Vec :: new ( ) ) ) ;
@@ -502,12 +537,18 @@ impl MultilineBuilder {
502
537
write ! ( buffer, [ content] ) ?;
503
538
buffer. write_element ( FormatElement :: Tag ( Tag :: EndEntry ) ) ?;
504
539
505
- buffer. write_element ( FormatElement :: Tag ( Tag :: StartEntry ) ) ?;
506
- write ! ( buffer, [ separator] ) ?;
507
- buffer. write_element ( FormatElement :: Tag ( Tag :: EndEntry ) ) ?;
540
+ if let Some ( separator) = separator {
541
+ buffer. write_element ( FormatElement :: Tag ( Tag :: StartEntry ) ) ?;
542
+ write ! ( buffer, [ separator] ) ?;
543
+ buffer. write_element ( FormatElement :: Tag ( Tag :: EndEntry ) ) ?;
544
+ }
508
545
}
509
546
MultilineLayout :: NoFill => {
510
547
write ! ( buffer, [ content, separator] ) ?;
548
+
549
+ if let Some ( separator) = separator {
550
+ write ! ( buffer, [ separator] ) ?;
551
+ }
511
552
}
512
553
} ;
513
554
buffer. into_vec ( )
0 commit comments