1use super::super::configuration::Configuration;
2use super::context::Context;
3use super::token_finder::TokenFinder;
4use dprint_core::formatting::conditions::if_true_or;
5use dprint_core::formatting::ir_helpers::SingleLineOptions;
6use dprint_core::formatting::*;
7use dprint_core_macros::sc;
8use jsonc_parser::ast::*;
9use jsonc_parser::common::Range;
10use jsonc_parser::common::Ranged;
11use jsonc_parser::tokens::TokenAndRange;
12use std::collections::HashSet;
13use std::rc::Rc;
14use text_lines::TextLines;
15
16use crate::configuration::*;
17
18pub fn generate(
19 parse_result: jsonc_parser::ParseResult,
20 text: &str,
21 config: &Configuration,
22 is_jsonc: bool,
23) -> PrintItems {
24 let comments = parse_result.comments.unwrap();
25 let tokens = parse_result.tokens.unwrap();
26 let node_value = parse_result.value;
27 let text_info = TextLines::new(text);
28 let mut context = Context {
29 config,
30 text,
31 text_info,
32 is_jsonc,
33 handled_comments: HashSet::new(),
34 parent_stack: Vec::new(),
35 current_node: None,
36 comments: &comments,
37 token_finder: TokenFinder::new(&tokens),
38 };
39
40 let mut items = PrintItems::new();
41 if let Some(node_value) = &node_value {
42 items.extend(gen_node(node_value.into(), &mut context));
43 items.extend(gen_trailing_comments_as_statements(node_value, &mut context));
44 } else if let Some(comments) = comments.get(&0) {
45 items.extend(gen_comments_as_statements(comments.iter(), None, &mut context));
46 }
47 items.push_condition(conditions::if_true(
48 "endOfFileNewLine",
49 Rc::new(|context| Some(context.writer_info.column_number > 0 || context.writer_info.line_number > 0)),
50 Signal::NewLine.into(),
51 ));
52
53 items
54}
55
56fn gen_node<'a>(node: Node<'a, 'a>, context: &mut Context<'a, '_>) -> PrintItems {
57 gen_node_with_inner(node, context, |items, _| items)
58}
59
60fn gen_node_with_inner<'a>(
61 node: Node<'a, 'a>,
62 context: &mut Context<'a, '_>,
63 inner_gen: impl FnOnce(PrintItems, &mut Context<'a, '_>) -> PrintItems,
64) -> PrintItems {
65 let past_current_node = context.current_node.replace(node);
67 let parent_end = past_current_node.as_ref().map(|n| n.end());
68 let node_end = node.end();
69 let is_root = past_current_node.is_none();
70
71 if let Some(past_current_node) = past_current_node {
72 context.parent_stack.push(past_current_node);
73 }
74
75 let mut items = PrintItems::new();
77
78 if let Some(comments) = context.comments.get(&node.start()) {
80 items.extend(gen_comments_as_leading(&node, comments.iter(), context));
81 }
82
83 if has_ignore_comment(&node, context) {
85 items.push_force_current_line_indentation();
86 items.extend(inner_gen(
87 ir_helpers::gen_from_raw_string(node.text(context.text)),
88 context,
89 ));
90 } else {
91 items.extend(inner_gen(gen_node_inner(&node, context), context))
92 }
93
94 if is_root || parent_end.is_some() && parent_end.unwrap() != node_end {
96 if let Some(comments) = context.comments.get(&node_end) {
97 items.extend(gen_comments_as_trailing(&node, comments.iter(), context));
98 }
99 }
100
101 context.current_node = context.parent_stack.pop();
102
103 return items;
104
105 #[inline]
106 fn gen_node_inner<'a>(node: &Node<'a, 'a>, context: &mut Context<'a, '_>) -> PrintItems {
107 match node {
108 Node::Array(node) => gen_array(node, context),
109 Node::BooleanLit(node) => node.value.to_string().into(),
110 Node::NullKeyword(_) => "null".into(),
111 Node::NumberLit(node) => node.value.to_string().into(),
112 Node::Object(node) => gen_object(node, context),
113 Node::ObjectProp(node) => gen_object_prop(node, context),
114 Node::StringLit(node) => gen_string_lit(node, context),
115 Node::WordLit(node) => gen_word_lit(node, context),
116 }
117 }
118}
119
120fn gen_array<'a>(node: &'a Array<'a>, context: &mut Context<'a, '_>) -> PrintItems {
121 let force_multi_lines = !context.config.array_prefer_single_line
122 && (should_break_up_single_line(node, context)
123 || context.text_info.line_index(node.start())
124 < node
125 .elements
126 .first()
127 .map(|p| context.text_info.line_index(p.start()))
128 .unwrap_or_else(|| context.text_info.line_index(node.start())));
129
130 gen_surrounded_by_tokens(
131 |context| {
132 let mut items = PrintItems::new();
133 items.extend(gen_comma_separated_values(
134 GenCommaSeparatedValuesOptions {
135 nodes: node.elements.iter().map(|x| Some(x.into())).collect(),
136 prefer_hanging: false,
137 force_use_new_lines: force_multi_lines,
138 allow_blank_lines: true,
139 single_line_space_at_start: false,
140 single_line_space_at_end: false,
141 custom_single_line_separator: None,
142 multi_line_options: ir_helpers::MultiLineOptions::surround_newlines_indented(),
143 force_possible_newline_at_start: false,
144 },
145 context,
146 ));
147 items
148 },
149 GenSurroundedByTokensOptions {
150 open_token: sc!("["),
151 close_token: sc!("]"),
152 range: node.range,
153 first_member: node.elements.first().map(|f| f.range()),
154 prefer_single_line_when_empty: true,
155 },
156 context,
157 )
158}
159
160fn gen_object<'a>(obj: &'a Object, context: &mut Context<'a, '_>) -> PrintItems {
161 let force_multi_lines = !context.config.object_prefer_single_line
162 && (should_break_up_single_line(obj, context)
163 || context.text_info.line_index(obj.start())
164 < obj
165 .properties
166 .first()
167 .map(|p| context.text_info.line_index(p.start()))
168 .unwrap_or_else(|| context.text_info.line_index(obj.end())));
169
170 gen_surrounded_by_tokens(
171 |context| {
172 let mut items = PrintItems::new();
173 items.extend(gen_comma_separated_values(
174 GenCommaSeparatedValuesOptions {
175 nodes: obj.properties.iter().map(|x| Some(Node::ObjectProp(x))).collect(),
176 prefer_hanging: false,
177 force_use_new_lines: force_multi_lines,
178 allow_blank_lines: true,
179 single_line_space_at_start: true,
180 single_line_space_at_end: true,
181 custom_single_line_separator: None,
182 multi_line_options: ir_helpers::MultiLineOptions::surround_newlines_indented(),
183 force_possible_newline_at_start: false,
184 },
185 context,
186 ));
187 items
188 },
189 GenSurroundedByTokensOptions {
190 open_token: sc!("{"),
191 close_token: sc!("}"),
192 range: obj.range,
193 first_member: obj.properties.first().map(|f| f.range()),
194 prefer_single_line_when_empty: false,
195 },
196 context,
197 )
198}
199
200fn gen_object_prop<'a>(node: &'a ObjectProp, context: &mut Context<'a, '_>) -> PrintItems {
201 let mut items = PrintItems::new();
202 items.extend(gen_node((&node.name).into(), context));
203 items.push_sc(sc!(": "));
204 items.extend(gen_node((&node.value).into(), context));
205
206 items
207}
208
209const DOUBLE_QUOTE_SC: &'static StringContainer = sc!("\"");
210
211fn gen_string_lit<'a>(node: &'a StringLit, context: &mut Context<'a, '_>) -> PrintItems {
212 let text = node.text(context.text);
213 let is_double_quotes = text.starts_with('"');
214 let mut items = PrintItems::new();
215 let text = &text[1..text.len() - 1];
216 items.push_sc(DOUBLE_QUOTE_SC);
217 if is_double_quotes {
218 items.push_string(text.to_string());
219 } else {
220 let text = text.replace("\\'", "'");
221 items.push_string(text.replace('"', "\\\""));
222 }
223 items.push_sc(DOUBLE_QUOTE_SC);
224 items
225}
226
227fn gen_word_lit<'a>(node: &'a WordLit<'a>, _: &mut Context<'a, '_>) -> PrintItems {
228 let mut items = PrintItems::new();
230 items.push_sc(DOUBLE_QUOTE_SC);
231 items.push_string(node.value.to_string());
232 items.push_sc(DOUBLE_QUOTE_SC);
233 items
234}
235
236struct GenCommaSeparatedValuesOptions<'a> {
237 nodes: Vec<Option<Node<'a, 'a>>>,
238 prefer_hanging: bool,
239 force_use_new_lines: bool,
240 allow_blank_lines: bool,
241 single_line_space_at_start: bool,
242 single_line_space_at_end: bool,
243 custom_single_line_separator: Option<PrintItems>,
244 multi_line_options: ir_helpers::MultiLineOptions,
245 force_possible_newline_at_start: bool,
246}
247
248fn gen_comma_separated_values<'a>(
249 opts: GenCommaSeparatedValuesOptions<'a>,
250 context: &mut Context<'a, '_>,
251) -> PrintItems {
252 let nodes = opts.nodes;
253 let indent_width = context.config.indent_width;
254 let compute_lines_span = opts.allow_blank_lines && opts.force_use_new_lines; ir_helpers::gen_separated_values(
256 |is_multi_line_or_hanging_ref| {
257 let mut generated_nodes = Vec::new();
258 let nodes_count = nodes.len();
259 for (i, value) in nodes.into_iter().enumerate() {
260 let (allow_inline_multi_line, allow_inline_single_line) = if let Some(value) = &value {
261 (value.kind() == NodeKind::Object, false)
262 } else {
263 (false, false)
264 };
265 let lines_span = if compute_lines_span {
266 value.as_ref().map(|x| ir_helpers::LinesSpan {
267 start_line: context.start_line_with_comments(x),
268 end_line: context.end_line_with_comments(x),
269 })
270 } else {
271 None
272 };
273 let items = ir_helpers::new_line_group({
274 let is_final_node = i == nodes_count - 1;
275 let use_comma_for_last = !is_final_node
276 || match context.config.trailing_commas {
277 TrailingCommaKind::Always => true,
278 TrailingCommaKind::Maintain => match &value {
279 Some(value) => context.token_finder.get_next_token_if_comma(&value.range()).is_some(),
280 None => false,
281 },
282 TrailingCommaKind::Jsonc => context.is_jsonc,
283 TrailingCommaKind::Never => false,
284 };
285 let maybe_comma = if !is_final_node {
286 ",".into()
287 } else if use_comma_for_last {
288 let is_multi_line = is_multi_line_or_hanging_ref.create_resolver();
289 if_true_or("is_multi_line", is_multi_line, ",".into(), PrintItems::new()).into()
290 } else {
291 PrintItems::new()
292 };
293 gen_comma_separated_value(value, maybe_comma, context)
294 });
295 generated_nodes.push(ir_helpers::GeneratedValue {
296 items,
297 lines_span,
298 allow_inline_multi_line,
299 allow_inline_single_line,
300 });
301 }
302
303 generated_nodes
304 },
305 ir_helpers::GenSeparatedValuesOptions {
306 prefer_hanging: opts.prefer_hanging,
307 force_use_new_lines: opts.force_use_new_lines,
308 allow_blank_lines: opts.allow_blank_lines,
309 single_line_options: SingleLineOptions {
310 space_at_start: opts.single_line_space_at_start,
311 space_at_end: opts.single_line_space_at_end,
312 separator: opts
313 .custom_single_line_separator
314 .unwrap_or_else(|| Signal::SpaceOrNewLine.into()),
315 },
316 indent_width,
317 multi_line_options: opts.multi_line_options,
318 force_possible_newline_at_start: opts.force_possible_newline_at_start,
319 },
320 )
321 .items
322}
323
324fn gen_comma_separated_value<'a>(
325 value: Option<Node<'a, 'a>>,
326 generated_comma: PrintItems,
327 context: &mut Context<'a, '_>,
328) -> PrintItems {
329 let mut items = PrintItems::new();
330 let comma_token = get_comma_token(&value, context);
331
332 if let Some(element) = value {
333 let generated_comma = generated_comma.into_rc_path();
334 items.extend(gen_node_with_inner(element, context, move |mut items, _| {
335 items.push_optional_path(generated_comma);
337 items
338 }));
339 } else {
340 items.extend(generated_comma);
341 }
342
343 if let Some(comma_token) = comma_token {
345 items.extend(gen_trailing_comments(comma_token, context));
346 }
347
348 return items;
349
350 fn get_comma_token<'a, 'b>(element: &Option<Node>, context: &mut Context<'a, 'b>) -> Option<&'b TokenAndRange<'a>> {
351 if let Some(element) = element {
352 context.token_finder.get_next_token_if_comma(element)
353 } else {
354 None
355 }
356 }
357}
358
359struct GenSurroundedByTokensOptions {
360 open_token: &'static StringContainer,
361 close_token: &'static StringContainer,
362 range: Range,
363 first_member: Option<Range>,
364 prefer_single_line_when_empty: bool,
365}
366
367fn gen_surrounded_by_tokens<'a, 'b>(
368 gen_inner: impl FnOnce(&mut Context<'a, 'b>) -> PrintItems,
369 opts: GenSurroundedByTokensOptions,
370 context: &mut Context<'a, 'b>,
371) -> PrintItems {
372 let open_token_end = opts.range.start + opts.open_token.text.len();
373 let close_token_start = opts.range.end - opts.close_token.text.len();
374
375 #[cfg(debug_assertions)]
377 context.assert_text(opts.range.start, open_token_end, opts.open_token.text);
378 #[cfg(debug_assertions)]
379 context.assert_text(close_token_start, opts.range.end, opts.close_token.text);
380
381 let mut items = PrintItems::new();
383 let open_token_start_line = context.text_info.line_index(opts.range.start);
384
385 items.push_sc(opts.open_token);
386 if let Some(first_member) = opts.first_member {
387 let first_member_start_line = context.text_info.line_index(first_member.start);
388 if open_token_start_line < first_member_start_line {
389 if let Some(trailing_comments) = context.comments.get(&open_token_end) {
390 items.extend(gen_first_line_trailing_comment(
391 open_token_start_line,
392 trailing_comments.iter(),
393 context,
394 ));
395 }
396 }
397 items.extend(gen_inner(context));
398
399 let before_trailing_comments_lc = LineAndColumn::new("beforeTrailingComments");
400 items.push_line_and_column(before_trailing_comments_lc);
401 items.extend(ir_helpers::with_indent(gen_trailing_comments_as_statements(
402 &Range::from_byte_index(open_token_end),
403 context,
404 )));
405 if let Some(leading_comments) = context.comments.get(&close_token_start) {
406 items.extend(ir_helpers::with_indent(gen_comments_as_statements(
407 leading_comments.iter(),
408 None,
409 context,
410 )));
411 }
412 items.push_condition(conditions::if_true(
413 "newLineIfHasCommentsAndNotStartOfNewLine",
414 Rc::new(move |context| {
415 let had_comments = !condition_helpers::is_at_same_position(context, before_trailing_comments_lc)?;
416 Some(had_comments && !context.writer_info.is_start_of_line())
417 }),
418 Signal::NewLine.into(),
419 ));
420 } else {
421 let range_end_line = context.text_info.line_index(opts.range.end);
422 let is_single_line = open_token_start_line == range_end_line;
423 if let Some(comments) = context.comments.get(&open_token_end) {
424 if !is_single_line {
426 items.extend(gen_first_line_trailing_comment(
427 open_token_start_line,
428 comments.iter(),
429 context,
430 ));
431 }
432
433 if has_unhandled_comment(comments.iter(), context) {
435 if is_single_line {
436 let indent_width = context.config.indent_width;
437 items.extend(
438 ir_helpers::gen_separated_values(
439 |_| {
440 let mut generated_comments = Vec::new();
441 for c in comments.iter() {
442 let start_line = context.text_info.line_index(c.start());
443 let end_line = context.text_info.line_index(c.end());
444 if let Some(items) = gen_comment(c, context) {
445 generated_comments.push(ir_helpers::GeneratedValue {
446 items,
447 lines_span: Some(ir_helpers::LinesSpan { start_line, end_line }),
448 allow_inline_multi_line: false,
449 allow_inline_single_line: false,
450 });
451 }
452 }
453 generated_comments
454 },
455 ir_helpers::GenSeparatedValuesOptions {
456 prefer_hanging: false,
457 force_use_new_lines: !is_single_line,
458 allow_blank_lines: true,
459 single_line_options: ir_helpers::SingleLineOptions {
460 space_at_start: false,
461 space_at_end: false,
462 separator: Signal::SpaceOrNewLine.into(),
463 },
464 indent_width,
465 multi_line_options: ir_helpers::MultiLineOptions::surround_newlines_indented(),
466 force_possible_newline_at_start: false,
467 },
468 )
469 .items,
470 );
471 } else {
472 items.push_signal(Signal::NewLine);
473 items.extend(ir_helpers::with_indent(gen_comments_as_statements(
474 comments.iter(),
475 None,
476 context,
477 )));
478 items.push_signal(Signal::NewLine);
479 }
480 }
481 } else if !is_single_line && !opts.prefer_single_line_when_empty {
482 items.push_signal(Signal::NewLine);
483 }
484 }
485
486 items.push_sc(opts.close_token);
487
488 return items;
489
490 fn gen_first_line_trailing_comment<'a: 'b, 'b>(
491 open_token_start_line: usize,
492 comments: impl Iterator<Item = &'b Comment<'a>>,
493 context: &mut Context,
494 ) -> PrintItems {
495 let mut items = PrintItems::new();
496 let mut comments = comments;
497 if let Some(first_comment) = comments.next() {
498 if first_comment.kind() == CommentKind::Line
499 && context.text_info.line_index(first_comment.start()) == open_token_start_line
500 {
501 if let Some(generated_comment) = gen_comment(first_comment, context) {
502 items.push_signal(Signal::StartForceNoNewLines);
503 items.push_space();
504 items.extend(generated_comment);
505 items.push_signal(Signal::FinishForceNoNewLines);
506 }
507 }
508 }
509 items
510 }
511}
512
513fn has_unhandled_comment<'a: 'b, 'b>(
516 mut comments: impl Iterator<Item = &'b Comment<'a>>,
517 context: &mut Context,
518) -> bool {
519 comments.any(|c| !context.has_handled_comment(c))
520}
521
522fn gen_trailing_comments(node: &dyn Ranged, context: &mut Context) -> PrintItems {
523 if let Some(trailing_comments) = context.comments.get(&node.end()) {
524 gen_comments_as_trailing(node, trailing_comments.iter(), context)
525 } else {
526 PrintItems::new()
527 }
528}
529
530fn gen_trailing_comments_as_statements(node: &dyn Ranged, context: &mut Context) -> PrintItems {
531 let unhandled_comments = get_trailing_comments_as_statements(node, context);
532 gen_comments_as_statements(unhandled_comments.into_iter(), Some(node), context)
533}
534
535fn get_trailing_comments_as_statements<'a, 'b>(
536 node: &dyn Ranged,
537 context: &mut Context<'a, 'b>,
538) -> Vec<&'b Comment<'a>> {
539 let mut comments = Vec::new();
540 let node_end_line = context.text_info.line_index(node.end());
541 if let Some(trailing_comments) = context.comments.get(&node.end()) {
542 for comment in trailing_comments.iter() {
543 if !context.has_handled_comment(comment) && node_end_line < context.text_info.line_index(comment.end()) {
544 comments.push(comment);
545 }
546 }
547 }
548 comments
549}
550
551fn gen_comments_as_statements<'a: 'b, 'b>(
552 comments: impl Iterator<Item = &'b Comment<'a>>,
553 last_node: Option<&dyn Ranged>,
554 context: &mut Context<'a, 'b>,
555) -> PrintItems {
556 let mut last_node = last_node;
557 let mut items = PrintItems::new();
558 for comment in comments {
559 if !context.has_handled_comment(comment) {
560 items.extend(gen_comment_based_on_last_node(
561 comment,
562 &last_node,
563 GenCommentBasedOnLastNodeOptions {
564 separate_with_newlines: true,
565 },
566 context,
567 ));
568 last_node = Some(comment);
569 }
570 }
571 items
572}
573
574fn gen_comments_as_leading<'a: 'b, 'b>(
575 node: &dyn Ranged,
576 comments: impl Iterator<Item = &'b Comment<'a>>,
577 context: &mut Context,
578) -> PrintItems {
579 let mut items = PrintItems::new();
580 let comments = comments.filter(|c| !context.has_handled_comment(c)).collect::<Vec<_>>();
581
582 if !comments.is_empty() {
583 let last_comment = comments.last().unwrap();
584 let last_comment_end_line = context.text_info.line_index(last_comment.end());
585 let last_comment_kind = last_comment.kind();
586 items.extend(gen_comment_collection(comments.into_iter(), None, Some(node), context));
587
588 let node_start_line = context.text_info.line_index(node.start());
589 if node_start_line > last_comment_end_line {
590 items.push_signal(Signal::NewLine);
591
592 if node_start_line - 1 > last_comment_end_line {
593 items.push_signal(Signal::NewLine);
594 }
595 } else if last_comment_kind == CommentKind::Block && node_start_line == last_comment_end_line {
596 items.push_signal(Signal::SpaceIfNotTrailing);
597 }
598 }
599
600 items
601}
602
603fn gen_comments_as_trailing<'a: 'b, 'b>(
604 node: &dyn Ranged,
605 comments: impl Iterator<Item = &'b Comment<'a>>,
606 context: &mut Context,
607) -> PrintItems {
608 let node_end_line = context.text_info.line_index(node.end());
610 let trailing_comments_on_same_line = comments
611 .filter(|c| context.text_info.line_index(c.start()) <= node_end_line)
612 .collect::<Vec<_>>();
613
614 let first_unhandled_comment = trailing_comments_on_same_line
615 .iter()
616 .find(|c| !context.has_handled_comment(c));
617 let mut items = PrintItems::new();
618
619 if let Some(Comment::Block(_)) = first_unhandled_comment {
620 items.push_space();
621 }
622
623 items.extend(gen_comment_collection(
624 trailing_comments_on_same_line.into_iter(),
625 Some(node),
626 None,
627 context,
628 ));
629
630 items
631}
632
633fn gen_comment_collection<'a: 'b, 'b>(
634 comments: impl Iterator<Item = &'b Comment<'a>>,
635 last_node: Option<&dyn Ranged>,
636 next_node: Option<&dyn Ranged>,
637 context: &mut Context,
638) -> PrintItems {
639 let mut last_node = last_node;
640 let mut items = PrintItems::new();
641 let next_node_start_line = next_node.map(|n| context.text_info.line_index(n.start()));
642
643 for comment in comments {
644 if !context.has_handled_comment(comment) {
645 items.extend(gen_comment_based_on_last_node(
646 comment,
647 &last_node,
648 GenCommentBasedOnLastNodeOptions {
649 separate_with_newlines: if let Some(next_node_start_line) = next_node_start_line {
650 context.text_info.line_index(comment.start()) != next_node_start_line
651 } else {
652 false
653 },
654 },
655 context,
656 ));
657 last_node = Some(comment);
658 }
659 }
660
661 items
662}
663
664struct GenCommentBasedOnLastNodeOptions {
665 separate_with_newlines: bool,
666}
667
668fn gen_comment_based_on_last_node(
669 comment: &Comment,
670 last_node: &Option<&dyn Ranged>,
671 opts: GenCommentBasedOnLastNodeOptions,
672 context: &mut Context,
673) -> PrintItems {
674 let mut items = PrintItems::new();
675 let mut pushed_ignore_new_lines = false;
676
677 if let Some(last_node) = last_node {
678 let comment_start_line = context.text_info.line_index(comment.start());
679 let last_node_end_line = context.text_info.line_index(last_node.end());
680
681 if opts.separate_with_newlines || comment_start_line > last_node_end_line {
682 items.push_signal(Signal::NewLine);
683
684 if comment_start_line > last_node_end_line + 1 {
685 items.push_signal(Signal::NewLine);
686 }
687 } else if comment.kind() == CommentKind::Line {
688 items.push_signal(Signal::StartForceNoNewLines);
689 items.push_space();
690 pushed_ignore_new_lines = true;
691 } else if last_node.text(context.text).starts_with("/*") {
692 items.push_space();
693 }
694 }
695
696 if let Some(generated_comment) = gen_comment(comment, context) {
697 items.extend(generated_comment);
698 }
699
700 if pushed_ignore_new_lines {
701 items.push_signal(Signal::FinishForceNoNewLines);
702 }
703
704 items
705}
706
707fn gen_comment(comment: &Comment, context: &mut Context) -> Option<PrintItems> {
708 if context.has_handled_comment(comment) {
710 return None;
711 }
712
713 context.mark_comment_handled(comment);
715 Some(match comment {
716 Comment::Block(comment) => ir_helpers::gen_js_like_comment_block(comment.text),
717 Comment::Line(comment) => {
718 ir_helpers::gen_js_like_comment_line(comment.text, context.config.comment_line_force_space_after_slashes)
719 }
720 })
721}
722
723fn has_ignore_comment(node: &dyn Ranged, context: &Context) -> bool {
724 if let Some(last_comment) = context.comments.get(&(node.start())).and_then(|c| c.last()) {
725 ir_helpers::text_has_dprint_ignore(last_comment.text(), &context.config.ignore_node_comment_text)
726 } else {
727 false
728 }
729}
730
731fn should_break_up_single_line(ranged: &impl Ranged, context: &Context) -> bool {
732 let range = ranged.range();
736
737 context.text_info.line_index(range.start) == context.text_info.line_index(range.end)
741 && range.width() > (context.config.line_width * 2) as usize
742}