diff --git a/crates/oxc_codegen/src/comment.rs b/crates/oxc_codegen/src/comment.rs index d958ddc7c1cd4..50a8a81245bff 100644 --- a/crates/oxc_codegen/src/comment.rs +++ b/crates/oxc_codegen/src/comment.rs @@ -1,6 +1,7 @@ -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; +use std::borrow::Cow; -use oxc_ast::{Comment, CommentKind}; +use oxc_ast::{Comment, CommentKind, ast::Program}; use oxc_syntax::identifier::is_line_terminator; use crate::{Codegen, LegalComment}; @@ -15,13 +16,6 @@ impl Codegen<'_> { { return; } - let move_legal_comments = { - let legal_comments = &self.options.legal_comments; - matches!( - legal_comments, - LegalComment::Eof | LegalComment::Linked(_) | LegalComment::External - ) - }; for comment in comments { // Omit pure comments because they are handled separately. if comment.is_pure() || comment.is_no_side_effects() { @@ -29,9 +23,7 @@ impl Codegen<'_> { } let mut add = false; if comment.is_legal() { - if move_legal_comments { - self.legal_comments.push(*comment); - } else if self.options.print_legal_comment() { + if self.options.print_legal_comment() { add = true; } } else if comment.is_leading() { @@ -142,8 +134,7 @@ impl Codegen<'_> { } CommentKind::Block => { // Print block comments with our own indentation. - let lines = comment_source.split(is_line_terminator); - for line in lines { + for line in comment_source.split(is_line_terminator) { if !line.starts_with("/*") { self.print_indent(); } @@ -156,25 +147,66 @@ impl Codegen<'_> { } } - pub(crate) fn try_print_eof_legal_comments(&mut self) { - match self.options.legal_comments.clone() { - LegalComment::Eof => { - let comments = self.legal_comments.drain(..).collect::>(); - if !comments.is_empty() { - self.print_hard_newline(); + /// Handle Eof / Linked / External Comments. + /// Return a list of comments of linked or external. + pub(crate) fn handle_eof_linked_or_external_comments( + &mut self, + program: &Program<'_>, + ) -> Vec { + let legal_comments = &self.options.legal_comments; + if matches!(legal_comments, LegalComment::None | LegalComment::Inline) { + return vec![]; + } + + // Dedupe legal comments for smaller output size. + let mut set = FxHashSet::default(); + let mut comments = vec![]; + + let source_text = program.source_text; + for comment in program.comments.iter().filter(|c| c.is_legal()) { + let mut text = Cow::Borrowed(comment.span.source_text(source_text)); + if comment.is_block() && text.contains(is_line_terminator) { + let mut buffer = String::with_capacity(text.len()); + // Print block comments with our own indentation. + for line in text.split(is_line_terminator) { + if !line.starts_with("/*") { + buffer.push('\t'); + } + buffer.push_str(line.trim_start()); + if !line.ends_with("*/") { + buffer.push('\n'); + } } + text = Cow::Owned(buffer); + } + if set.insert(text) { + comments.push(*comment); + } + } + + if comments.is_empty() { + return vec![]; + } + + match legal_comments { + LegalComment::Eof => { + self.print_hard_newline(); for c in comments { self.print_comment(&c); self.print_hard_newline(); } + vec![] } LegalComment::Linked(path) => { + let path = path.clone(); self.print_hard_newline(); self.print_str("/*! For license information please see "); self.print_str(&path); self.print_str(" */"); + comments } - _ => {} + LegalComment::External => comments, + LegalComment::None | LegalComment::Inline => unreachable!(), } } } diff --git a/crates/oxc_codegen/src/lib.rs b/crates/oxc_codegen/src/lib.rs index 02e211a9a3356..11c1bf26d8e46 100644 --- a/crates/oxc_codegen/src/lib.rs +++ b/crates/oxc_codegen/src/lib.rs @@ -107,8 +107,6 @@ pub struct Codegen<'a> { // Builders comments: CommentsMap, - legal_comments: Vec, - sourcemap_builder: Option, } @@ -157,7 +155,6 @@ impl<'a> Codegen<'a> { indent: 0, quote: Quote::Double, comments: CommentsMap::default(), - legal_comments: vec![], sourcemap_builder: None, } } @@ -199,10 +196,10 @@ impl<'a> Codegen<'a> { self.sourcemap_builder = Some(SourcemapBuilder::new(path, program.source_text)); } program.print(&mut self, Context::default()); - self.try_print_eof_legal_comments(); + let legal_comments = self.handle_eof_linked_or_external_comments(program); let code = self.code.into_string(); let map = self.sourcemap_builder.map(SourcemapBuilder::into_sourcemap); - CodegenReturn { code, map, legal_comments: self.legal_comments } + CodegenReturn { code, map, legal_comments } } /// Turn what's been built so far into a string. Like [`build`], diff --git a/crates/oxc_codegen/tests/integration/snapshots/legal_eof_comments.snap b/crates/oxc_codegen/tests/integration/snapshots/legal_eof_comments.snap index 882b8431b32ce..ed88cc0a874b0 100644 --- a/crates/oxc_codegen/tests/integration/snapshots/legal_eof_comments.snap +++ b/crates/oxc_codegen/tests/integration/snapshots/legal_eof_comments.snap @@ -9,7 +9,6 @@ foo;bar; foo; bar; -/* @license */ /* @license */ ########## 1 diff --git a/crates/oxc_codegen/tests/integration/snapshots/legal_eof_minify_comments.snap b/crates/oxc_codegen/tests/integration/snapshots/legal_eof_minify_comments.snap index b3291dde9bb48..924ff56abb977 100644 --- a/crates/oxc_codegen/tests/integration/snapshots/legal_eof_minify_comments.snap +++ b/crates/oxc_codegen/tests/integration/snapshots/legal_eof_minify_comments.snap @@ -8,7 +8,6 @@ foo;bar; ---------- foo;bar; /* @license */ -/* @license */ ########## 1 /* @license */ diff --git a/crates/oxc_codegen/tests/integration/snapshots/legal_linked_comments.snap b/crates/oxc_codegen/tests/integration/snapshots/legal_linked_comments.snap index 4de133c25a30f..273152bb5a881 100644 --- a/crates/oxc_codegen/tests/integration/snapshots/legal_linked_comments.snap +++ b/crates/oxc_codegen/tests/integration/snapshots/legal_linked_comments.snap @@ -96,7 +96,6 @@ function foo() { /** * @preserve */ -/*! For license information please see test.js */ ########## 8 /** * @preserve @@ -106,5 +105,3 @@ function foo() { /** * @preserve */ - -/*! For license information please see test.js */