diff --git a/crates/swc_ecma_ast/src/source_map.rs b/crates/swc_ecma_ast/src/source_map.rs index 6b71be338593..27440fea7491 100644 --- a/crates/swc_ecma_ast/src/source_map.rs +++ b/crates/swc_ecma_ast/src/source_map.rs @@ -35,15 +35,12 @@ pub trait SourceMapperExt { false } - fn should_write_separating_line_terminator( + fn should_write_separating_line_terminator( &self, - prev: Option

, - next: Option, + prev: Option, + next: Option, format: ListFormat, ) -> bool { - let prev = prev.map(|s| s.span()); - let next = next.map(|s| s.span()); - if format.contains(ListFormat::MultiLine) { return true; } @@ -63,10 +60,10 @@ pub trait SourceMapperExt { false } - fn should_write_leading_line_terminator( + fn should_write_leading_line_terminator( &self, parent_node: Span, - children: &[N], + first_child: Option, format: ListFormat, ) -> bool { if format.contains(ListFormat::MultiLine) { @@ -78,11 +75,11 @@ pub trait SourceMapperExt { return true; } - if children.is_empty() { + if first_child.is_none() { return !self.is_on_same_line(parent_node.lo(), parent_node.hi()); } - let first_child = children[0].span(); + let first_child = first_child.unwrap(); if parent_node.is_synthesized() || first_child.is_synthesized() { return first_child.starts_on_new_line(format); } @@ -93,10 +90,10 @@ pub trait SourceMapperExt { } } - fn should_write_closing_line_terminator( + fn should_write_closing_line_terminator( &self, parent_node: Span, - children: &[N], + last_child: Option, format: ListFormat, ) -> bool { if format.contains(ListFormat::MultiLine) { @@ -108,11 +105,12 @@ pub trait SourceMapperExt { return true; } - if children.is_empty() { + if last_child.is_none() { return !self.is_on_same_line(parent_node.lo(), parent_node.hi()); } - let last_child = children[children.len() - 1].span(); + let last_child = last_child.unwrap(); + if parent_node.is_synthesized() || last_child.is_synthesized() { last_child.starts_on_new_line(format) } else { diff --git a/crates/swc_ecma_codegen/src/lib.rs b/crates/swc_ecma_codegen/src/lib.rs index ab0ee736f06e..d7c5e0d85860 100644 --- a/crates/swc_ecma_codegen/src/lib.rs +++ b/crates/swc_ecma_codegen/src/lib.rs @@ -2155,29 +2155,32 @@ where ) } - #[allow(clippy::cognitive_complexity)] - fn emit_list5( + /// This method exists to reduce compile time. + #[inline(never)] + fn emit_first_of_list5( &mut self, parent_node: Span, - children: Option<&[N]>, + children: Option, format: ListFormat, start: usize, count: usize, - ) -> Result { + ) -> Option { if children.is_none() && format.contains(ListFormat::OptionalIfUndefined) { - return Ok(()); + return Some(Ok(())); } - let is_empty = children.is_none() || start > children.unwrap().len() || count == 0; + let is_empty = children.is_none() || start > children.unwrap() || count == 0; if is_empty && format.contains(ListFormat::OptionalIfEmpty) { - return Ok(()); + return Some(Ok(())); } if format.contains(ListFormat::BracketsMask) { - self.wr.write_punct(None, format.opening_bracket())?; + if let Err(err) = self.wr.write_punct(None, format.opening_bracket()) { + return Some(Err(err)); + } if is_empty { - self.emit_trailing_comments_of_pos( + if let Err(err) = self.emit_trailing_comments_of_pos( { // TODO: children.lo() @@ -2185,11 +2188,201 @@ where }, true, false, - )?; + ) { + return Some(Err(err)); + } + } + } + + None + } + + /// This method exists to reduce compile time. + #[inline(never)] + fn emit_pre_child_for_list5( + &mut self, + parent_node: Span, + format: ListFormat, + previous_sibling: Option, + child: Span, + should_decrease_indent_after_emit: &mut bool, + should_emit_intervening_comments: &mut bool, + ) -> Result { + // Write the delimiter if this is not the first node. + if let Some(previous_sibling) = previous_sibling { + // i.e + // function commentedParameters( + // /* Parameter a */ + // a + // /* End of parameter a */ + // -> this comment isn't considered to be trailing comment of parameter "a" due + // to newline , + if format.contains(ListFormat::DelimitersMask) + && previous_sibling.hi != parent_node.hi() + && self.comments.is_some() + { + self.emit_leading_comments(previous_sibling.hi(), true)?; + } + + self.write_delim(format)?; + + // Write either a line terminator or whitespace to separate the elements. + + if self.cm.should_write_separating_line_terminator( + Some(previous_sibling), + Some(child), + format, + ) { + // If a synthesized node in a single-line list starts on a new + // line, we should increase the indent. + if (format & (ListFormat::LinesMask | ListFormat::Indented)) + == ListFormat::SingleLine + && !self.cfg.minify + { + self.wr.increase_indent()?; + *should_decrease_indent_after_emit = true; + } + + if !self.cfg.minify { + self.wr.write_line()?; + } + *should_emit_intervening_comments = false; + } else if format.contains(ListFormat::SpaceBetweenSiblings) { + formatting_space!(self); + } + } + + Ok(()) + } + + /// This method exists to reduce compile time. + #[inline(never)] + fn emit_list_finisher_of_list5( + &mut self, + parent_node: Span, + format: ListFormat, + previous_sibling: Option, + last_child: Option, + ) -> Result { + // Write a trailing comma, if requested. + let has_trailing_comma = format.contains(ListFormat::ForceTrailingComma) + || format.contains(ListFormat::AllowTrailingComma) && { + if parent_node.is_dummy() { + false + } else { + match self.cm.span_to_snippet(parent_node) { + Ok(snippet) => { + if snippet.len() < 3 { + false + } else { + let last_char = snippet.chars().last().unwrap(); + snippet[..snippet.len() - last_char.len_utf8()] + .trim() + .ends_with(',') + } + } + _ => false, + } + } + }; + + if has_trailing_comma + && format.contains(ListFormat::CommaDelimited) + && (!self.cfg.minify || !format.contains(ListFormat::CanSkipTrailingComma)) + { + punct!(self, ","); + formatting_space!(self); + } + + { + // Emit any trailing comment of the last element in the list + // i.e + // var array = [... + // 2 + // /* end of element 2 */ + // ]; + + let emit_trailing_comments = { + // TODO: + // + // !(getEmitFlags(previousSibling).contains(EmitFlags::NoTrailingComments)) + + true + }; + + if let Some(previous_sibling) = previous_sibling { + if format.contains(ListFormat::DelimitersMask) + && previous_sibling.hi() != parent_node.hi() + && emit_trailing_comments + && self.comments.is_some() + { + self.emit_leading_comments(previous_sibling.hi(), true)?; + } + } + } + + // Decrease the indent, if requested. + if format.contains(ListFormat::Indented) && !self.cfg.minify { + self.wr.decrease_indent()?; + } + + // Write the closing line terminator or closing whitespace. + if self + .cm + .should_write_closing_line_terminator(parent_node, last_child, format) + { + if !self.cfg.minify { + self.wr.write_line()?; } + } else if format.contains(ListFormat::SpaceBetweenBraces) && !self.cfg.minify { + self.wr.write_space()?; } - // self.handlers.onBeforeEmitNodeArray(children); + Ok(()) + } + + /// This method exists to reduce compile time. + #[inline(never)] + fn emit_last_of_list5( + &mut self, + parent_node: Span, + is_empty: bool, + format: ListFormat, + start: usize, + count: usize, + ) -> Result { + if format.contains(ListFormat::BracketsMask) { + if is_empty { + self.emit_leading_comments( + { + //TODO: children.hi() + + parent_node.hi() + }, + true, + )?; // Emit leading comments within empty lists + } + self.wr.write_punct(None, format.closing_bracket())?; + } + + Ok(()) + } + + fn emit_list5( + &mut self, + parent_node: Span, + children: Option<&[N]>, + format: ListFormat, + start: usize, + count: usize, + ) -> Result { + if let Some(result) = + self.emit_first_of_list5(parent_node, children.map(|v| v.len()), format, start, count) + { + return result; + } + + let is_empty = children.is_none() || start > children.unwrap().len() || count == 0; if is_empty { // Write a line terminator if the parent node was multi-line @@ -2211,10 +2404,11 @@ where let may_emit_intervening_comments = !format.intersects(ListFormat::NoInterveningComments); let mut should_emit_intervening_comments = may_emit_intervening_comments; - if self - .cm - .should_write_leading_line_terminator(parent_node, children, format) - { + if self.cm.should_write_leading_line_terminator( + parent_node, + children.first().map(|v| v.span()), + format, + ) { if !self.cfg.minify { self.wr.write_line()?; } @@ -2234,49 +2428,14 @@ where for i in 0..count { let child = &children[start + i]; - // Write the delimiter if this is not the first node. - if let Some(previous_sibling) = previous_sibling { - // i.e - // function commentedParameters( - // /* Parameter a */ - // a - // /* End of parameter a */ - // -> this comment isn't considered to be trailing comment of parameter "a" due - // to newline , - if format.contains(ListFormat::DelimitersMask) - && previous_sibling.hi != parent_node.hi() - && self.comments.is_some() - { - self.emit_leading_comments(previous_sibling.hi(), true)?; - } - - self.write_delim(format)?; - - // Write either a line terminator or whitespace to separate the elements. - - if self.cm.should_write_separating_line_terminator( - Some(previous_sibling), - Some(child), - format, - ) { - // If a synthesized node in a single-line list starts on a new - // line, we should increase the indent. - if (format & (ListFormat::LinesMask | ListFormat::Indented)) - == ListFormat::SingleLine - && !self.cfg.minify - { - self.wr.increase_indent()?; - should_decrease_indent_after_emit = true; - } - - if !self.cfg.minify { - self.wr.write_line()?; - } - should_emit_intervening_comments = false; - } else if format.contains(ListFormat::SpaceBetweenSiblings) { - formatting_space!(self); - } - } + self.emit_pre_child_for_list5( + parent_node, + format, + previous_sibling, + child.span(), + &mut should_decrease_indent_after_emit, + &mut should_emit_intervening_comments, + )?; child.emit_with(self)?; @@ -2298,97 +2457,17 @@ where previous_sibling = Some(child.span()); } - // Write a trailing comma, if requested. - let has_trailing_comma = format.contains(ListFormat::ForceTrailingComma) - || format.contains(ListFormat::AllowTrailingComma) && { - if parent_node.is_dummy() { - false - } else { - match self.cm.span_to_snippet(parent_node) { - Ok(snippet) => { - if snippet.len() < 3 { - false - } else { - let last_char = snippet.chars().last().unwrap(); - snippet[..snippet.len() - last_char.len_utf8()] - .trim() - .ends_with(',') - } - } - _ => false, - } - } - }; - - if has_trailing_comma - && format.contains(ListFormat::CommaDelimited) - && (!self.cfg.minify || !format.contains(ListFormat::CanSkipTrailingComma)) - { - punct!(self, ","); - formatting_space!(self); - } - - { - // Emit any trailing comment of the last element in the list - // i.e - // var array = [... - // 2 - // /* end of element 2 */ - // ]; - - let emit_trailing_comments = { - // TODO: - // - // !(getEmitFlags(previousSibling).contains(EmitFlags::NoTrailingComments)) - - true - }; - - if let Some(previous_sibling) = previous_sibling { - if format.contains(ListFormat::DelimitersMask) - && previous_sibling.hi() != parent_node.hi() - && emit_trailing_comments - && self.comments.is_some() - { - self.emit_leading_comments(previous_sibling.hi(), true)?; - } - } - } - - // Decrease the indent, if requested. - if format.contains(ListFormat::Indented) && !self.cfg.minify { - self.wr.decrease_indent()?; - } - - // Write the closing line terminator or closing whitespace. - if self - .cm - .should_write_closing_line_terminator(parent_node, children, format) - { - if !self.cfg.minify { - self.wr.write_line()?; - } - } else if format.contains(ListFormat::SpaceBetweenBraces) && !self.cfg.minify { - self.wr.write_space()?; - } + self.emit_list_finisher_of_list5( + parent_node, + format, + previous_sibling, + children.last().map(|v| v.span()), + )?; } // self.handlers.onAfterEmitNodeArray(children); - if format.contains(ListFormat::BracketsMask) { - if is_empty { - self.emit_leading_comments( - { - //TODO: children.hi() - - parent_node.hi() - }, - true, - )?; // Emit leading comments within empty lists - } - self.wr.write_punct(None, format.closing_bracket())?; - } - + self.emit_last_of_list5(parent_node, is_empty, format, start, count)?; Ok(()) } }