Skip to content

Commit c29b1b8

Browse files
committed
feat(codegen): deduplicate repeated legal comments (#11069)
related: evanw/esbuild@a54916b closes #10688
1 parent ef72143 commit c29b1b8

File tree

5 files changed

+55
-31
lines changed

5 files changed

+55
-31
lines changed

crates/oxc_codegen/src/comment.rs

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use rustc_hash::FxHashMap;
1+
use rustc_hash::{FxHashMap, FxHashSet};
2+
use std::borrow::Cow;
23

3-
use oxc_ast::{Comment, CommentKind};
4+
use oxc_ast::{Comment, CommentKind, ast::Program};
45
use oxc_syntax::identifier::is_line_terminator;
56

67
use crate::{Codegen, LegalComment};
@@ -15,23 +16,14 @@ impl Codegen<'_> {
1516
{
1617
return;
1718
}
18-
let move_legal_comments = {
19-
let legal_comments = &self.options.legal_comments;
20-
matches!(
21-
legal_comments,
22-
LegalComment::Eof | LegalComment::Linked(_) | LegalComment::External
23-
)
24-
};
2519
for comment in comments {
2620
// Omit pure comments because they are handled separately.
2721
if comment.is_pure() || comment.is_no_side_effects() {
2822
continue;
2923
}
3024
let mut add = false;
3125
if comment.is_legal() {
32-
if move_legal_comments {
33-
self.legal_comments.push(*comment);
34-
} else if self.options.print_legal_comment() {
26+
if self.options.print_legal_comment() {
3527
add = true;
3628
}
3729
} else if comment.is_leading() {
@@ -142,8 +134,7 @@ impl Codegen<'_> {
142134
}
143135
CommentKind::Block => {
144136
// Print block comments with our own indentation.
145-
let lines = comment_source.split(is_line_terminator);
146-
for line in lines {
137+
for line in comment_source.split(is_line_terminator) {
147138
if !line.starts_with("/*") {
148139
self.print_indent();
149140
}
@@ -156,25 +147,66 @@ impl Codegen<'_> {
156147
}
157148
}
158149

159-
pub(crate) fn try_print_eof_legal_comments(&mut self) {
160-
match self.options.legal_comments.clone() {
161-
LegalComment::Eof => {
162-
let comments = self.legal_comments.drain(..).collect::<Vec<_>>();
163-
if !comments.is_empty() {
164-
self.print_hard_newline();
150+
/// Handle Eof / Linked / External Comments.
151+
/// Return a list of comments of linked or external.
152+
pub(crate) fn handle_eof_linked_or_external_comments(
153+
&mut self,
154+
program: &Program<'_>,
155+
) -> Vec<Comment> {
156+
let legal_comments = &self.options.legal_comments;
157+
if matches!(legal_comments, LegalComment::None | LegalComment::Inline) {
158+
return vec![];
159+
}
160+
161+
// Dedupe legal comments for smaller output size.
162+
let mut set = FxHashSet::default();
163+
let mut comments = vec![];
164+
165+
let source_text = program.source_text;
166+
for comment in program.comments.iter().filter(|c| c.is_legal()) {
167+
let mut text = Cow::Borrowed(comment.span.source_text(source_text));
168+
if comment.is_block() && text.contains(is_line_terminator) {
169+
let mut buffer = String::with_capacity(text.len());
170+
// Print block comments with our own indentation.
171+
for line in text.split(is_line_terminator) {
172+
if !line.starts_with("/*") {
173+
buffer.push('\t');
174+
}
175+
buffer.push_str(line.trim_start());
176+
if !line.ends_with("*/") {
177+
buffer.push('\n');
178+
}
165179
}
180+
text = Cow::Owned(buffer);
181+
}
182+
if set.insert(text) {
183+
comments.push(*comment);
184+
}
185+
}
186+
187+
if comments.is_empty() {
188+
return vec![];
189+
}
190+
191+
match legal_comments {
192+
LegalComment::Eof => {
193+
self.print_hard_newline();
166194
for c in comments {
167195
self.print_comment(&c);
168196
self.print_hard_newline();
169197
}
198+
vec![]
170199
}
171200
LegalComment::Linked(path) => {
201+
let path = path.clone();
172202
self.print_hard_newline();
173203
self.print_str("/*! For license information please see ");
174204
self.print_str(&path);
175205
self.print_str(" */");
206+
comments
176207
}
177-
_ => {}
208+
LegalComment::External => comments,
209+
LegalComment::None | LegalComment::Inline => unreachable!(),
178210
}
179211
}
180212
}

crates/oxc_codegen/src/lib.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ pub struct Codegen<'a> {
107107
// Builders
108108
comments: CommentsMap,
109109

110-
legal_comments: Vec<Comment>,
111-
112110
sourcemap_builder: Option<SourcemapBuilder>,
113111
}
114112

@@ -157,7 +155,6 @@ impl<'a> Codegen<'a> {
157155
indent: 0,
158156
quote: Quote::Double,
159157
comments: CommentsMap::default(),
160-
legal_comments: vec![],
161158
sourcemap_builder: None,
162159
}
163160
}
@@ -199,10 +196,10 @@ impl<'a> Codegen<'a> {
199196
self.sourcemap_builder = Some(SourcemapBuilder::new(path, program.source_text));
200197
}
201198
program.print(&mut self, Context::default());
202-
self.try_print_eof_legal_comments();
199+
let legal_comments = self.handle_eof_linked_or_external_comments(program);
203200
let code = self.code.into_string();
204201
let map = self.sourcemap_builder.map(SourcemapBuilder::into_sourcemap);
205-
CodegenReturn { code, map, legal_comments: self.legal_comments }
202+
CodegenReturn { code, map, legal_comments }
206203
}
207204

208205
/// Turn what's been built so far into a string. Like [`build`],

crates/oxc_codegen/tests/integration/snapshots/legal_eof_comments.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ foo;bar;
99
foo;
1010
bar;
1111

12-
/* @license */
1312
/* @license */
1413

1514
########## 1

crates/oxc_codegen/tests/integration/snapshots/legal_eof_minify_comments.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ foo;bar;
88
----------
99
foo;bar;
1010
/* @license */
11-
/* @license */
1211

1312
########## 1
1413
/* @license */

crates/oxc_codegen/tests/integration/snapshots/legal_linked_comments.snap

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ function foo() {
9696
/**
9797
* @preserve
9898
*/
99-
/*! For license information please see test.js */
10099
########## 8
101100
/**
102101
* @preserve
@@ -106,5 +105,3 @@ function foo() {
106105
/**
107106
* @preserve
108107
*/
109-
110-
/*! For license information please see test.js */

0 commit comments

Comments
 (0)