Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions crates/oxc_ast/src/ast/comment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ pub enum CommentAnnotation {
#[default]
None = 0,

/// `/** jsdoc */`
/// <https://jsdoc.app>
Jsdoc = 1,

/// Legal Comment
/// e.g. `/* @license */`, `/* @preserve */`, or starts with `//!` or `/*!`.
///
/// <https://esbuild.github.io/api/#legal-comments>
Legal = 2,
Legal = 1,

/// `/** jsdoc */`
/// <https://jsdoc.app>
Jsdoc = 2,

/// `/* #__PURE__ */`
/// <https://github.com/javascript-compiler-hints/compiler-notations-spec>
Expand Down
100 changes: 35 additions & 65 deletions crates/oxc_codegen/src/comment.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use oxc_span::{GetSpan, Span};
use rustc_hash::FxHashMap;

use oxc_ast::{Comment, CommentKind, ast::Argument};
use oxc_ast::{Comment, CommentKind};
use oxc_syntax::identifier::is_line_terminator;

use crate::{Codegen, LegalComment};
Expand All @@ -10,7 +9,12 @@ pub type CommentsMap = FxHashMap</* attached_to */ u32, Vec<Comment>>;

impl Codegen<'_> {
pub(crate) fn build_comments(&mut self, comments: &[Comment]) {
self.comments.reserve(comments.len());
if !self.options.comments
&& self.options.legal_comments.is_none()
&& !self.options.annotation_comments
{
return;
}
let move_legal_comments = {
let legal_comments = &self.options.legal_comments;
matches!(
Expand All @@ -23,91 +27,57 @@ impl Codegen<'_> {
if comment.is_pure() || comment.is_no_side_effects() {
continue;
}
if comment.is_legal() && move_legal_comments {
self.legal_comments.push(*comment);
let mut add = false;
if comment.is_legal() {
if move_legal_comments {
self.legal_comments.push(*comment);
} else if self.options.print_legal_comment() {
add = true;
}
} else if comment.is_leading() {
if comment.is_annotation() {
if self.options.print_annotation_comment() {
add = true;
}
} else if self.options.print_normal_comment() {
add = true;
}
}
if add {
self.comments.entry(comment.attached_to).or_default().push(*comment);
}
self.comments.entry(comment.attached_to).or_default().push(*comment);
}
}

pub(crate) fn has_comment(&self, start: u32) -> bool {
self.comments.contains_key(&start)
}

pub(crate) fn contains_comment_in_call_like_expression(
&self,
span: Span,
arguments: &[Argument<'_>],
) -> (bool, bool) {
let has_comment_before_right_paren =
self.print_annotation_comment && span.end > 0 && self.has_comment(span.end - 1);

let has_comment = has_comment_before_right_paren
|| self.print_annotation_comment
&& arguments.iter().any(|item| self.has_comment(item.span().start));

(has_comment, has_comment_before_right_paren)
}

/// Whether to keep leading comments.
fn should_keep_leading_comment(comment: &Comment) -> bool {
comment.preceded_by_newline && comment.is_annotation()
}

pub(crate) fn print_leading_comments(&mut self, start: u32) {
if !self.print_any_comment {
return;
if let Some(comments) = self.comments.remove(&start) {
self.print_comments(&comments);
}
let Some(comments) = self.comments.remove(&start) else {
return;
};
let comments =
comments.into_iter().filter(Self::should_keep_leading_comment).collect::<Vec<_>>();
self.print_comments(&comments);
}

pub(crate) fn get_statement_comments(&mut self, start: u32) -> Option<Vec<Comment>> {
let comments = self.comments.remove(&start)?;

let mut leading_comments = vec![];

for comment in comments {
if comment.is_legal() {
match &self.options.legal_comments {
LegalComment::None if self.options.comments => {
leading_comments.push(comment);
continue;
}
LegalComment::Inline => {
leading_comments.push(comment);
continue;
}
LegalComment::Eof | LegalComment::Linked(_) | LegalComment::External => {
/* noop, handled by `build_comments`. */
continue;
}
LegalComment::None => {}
}
}
if Self::should_keep_leading_comment(&comment) {
leading_comments.push(comment);
}
if self.comments.is_empty() {
return None;
}

Some(leading_comments)
self.comments.remove(&start)
}

/// A statement comment also includes legal comments
#[inline]
pub(crate) fn print_statement_comments(&mut self, start: u32) {
if self.print_any_comment {
if let Some(comments) = self.get_statement_comments(start) {
self.print_comments(&comments);
}
if let Some(comments) = self.get_statement_comments(start) {
self.print_comments(&comments);
}
}

pub(crate) fn print_expr_comments(&mut self, start: u32) -> bool {
if self.comments.is_empty() {
return false;
}
let Some(comments) = self.comments.remove(&start) else { return false };

for comment in &comments {
Expand Down
103 changes: 20 additions & 83 deletions crates/oxc_codegen/src/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,8 @@ impl Gen for Program<'_> {
if let Some(hashbang) = &self.hashbang {
hashbang.print(p, ctx);
}
for directive in &self.directives {
directive.print(p, ctx);
}
for stmt in &self.body {
stmt.print(p, ctx);
p.print_semicolon_if_needed();
}
p.print_directives_and_statements(&self.directives, &self.body, ctx);
p.print_semicolon_if_needed();
// Print trailing statement comments.
p.print_statement_comments(self.span.end);
}
Expand Down Expand Up @@ -142,7 +137,7 @@ impl Gen for Statement<'_> {
}
Self::FunctionDeclaration(decl) => {
p.print_statement_comments(decl.span.start);
if decl.pure && p.print_annotation_comment {
if decl.pure && p.options.print_annotation_comment() {
p.print_indent();
p.print_str(NO_SIDE_EFFECTS_NEW_LINE_COMMENT);
}
Expand Down Expand Up @@ -742,27 +737,19 @@ impl Gen for Function<'_> {
impl Gen for FunctionBody<'_> {
fn r#gen(&self, p: &mut Codegen, ctx: Context) {
let span_end = self.span.end;
let comments_at_end = if p.print_any_comment && span_end > 0 {
p.get_statement_comments(span_end - 1)
} else {
None
};
let is_empty = if self.is_empty() {
comments_at_end.is_none() || comments_at_end.as_ref().is_some_and(Vec::is_empty)
let comments_at_end =
if span_end > 0 { p.get_statement_comments(span_end - 1) } else { None };
let single_line = if self.is_empty() {
comments_at_end.as_ref().is_none_or(|comments| comments.iter().all(|c| c.is_block()))
} else {
false
};
p.print_curly_braces(self.span, is_empty, |p| {
for directive in &self.directives {
directive.print(p, ctx);
}
for stmt in &self.statements {
p.print_semicolon_if_needed();
stmt.print(p, ctx);
}
p.print_curly_braces(self.span, single_line, |p| {
p.print_directives_and_statements(&self.directives, &self.statements, ctx);
// Print trailing statement comments.
if let Some(comments) = comments_at_end {
p.print_comments(&comments);
p.print_next_indent_as_space = false;
}
});
p.needs_semicolon = false;
Expand Down Expand Up @@ -953,7 +940,7 @@ impl Gen for ExportNamedDeclaration<'_> {
fn r#gen(&self, p: &mut Codegen, ctx: Context) {
p.print_statement_comments(self.span.start);
if let Some(Declaration::FunctionDeclaration(func)) = &self.declaration {
if func.pure && p.print_annotation_comment {
if func.pure && p.options.print_annotation_comment() {
p.print_str(NO_SIDE_EFFECTS_NEW_LINE_COMMENT);
}
}
Expand Down Expand Up @@ -1100,7 +1087,7 @@ impl Gen for ExportDefaultDeclaration<'_> {
fn r#gen(&self, p: &mut Codegen, ctx: Context) {
p.print_statement_comments(self.span.start);
if let ExportDefaultDeclarationKind::FunctionDeclaration(func) = &self.declaration {
if func.pure && p.print_annotation_comment {
if func.pure && p.options.print_annotation_comment() {
p.print_str(NO_SIDE_EFFECTS_NEW_LINE_COMMENT);
}
}
Expand Down Expand Up @@ -1149,13 +1136,13 @@ impl GenExpr for Expression<'_> {
Self::ArrayExpression(expr) => expr.print(p, ctx),
Self::ObjectExpression(expr) => expr.print_expr(p, precedence, ctx),
Self::FunctionExpression(func) => {
if func.pure && p.print_annotation_comment {
if func.pure && p.options.print_annotation_comment() {
p.print_str(NO_SIDE_EFFECTS_COMMENT);
}
func.print(p, ctx);
}
Self::ArrowFunctionExpression(func) => {
if func.pure && p.print_annotation_comment {
if func.pure && p.options.print_annotation_comment() {
p.print_str(NO_SIDE_EFFECTS_COMMENT);
}
func.print_expr(p, precedence, ctx);
Expand Down Expand Up @@ -1398,7 +1385,7 @@ impl GenExpr for CallExpression<'_> {
let is_statement = p.start_of_stmt == p.code_len();
let is_export_default = p.start_of_default_export == p.code_len();
let mut wrap = precedence >= Precedence::New || ctx.intersects(Context::FORBID_CALL);
let pure = self.pure && p.print_annotation_comment;
let pure = self.pure && p.options.print_annotation_comment();
if precedence >= Precedence::Postfix && pure {
wrap = true;
}
Expand All @@ -1420,22 +1407,7 @@ impl GenExpr for CallExpression<'_> {
if let Some(type_parameters) = &self.type_arguments {
type_parameters.print(p, ctx);
}
p.print_ascii_byte(b'(');

let (has_comment, has_comment_before_right_paren) =
p.contains_comment_in_call_like_expression(self.span, self.arguments.as_slice());
if has_comment {
p.indent();
p.print_list_with_comments(self.arguments.as_slice(), ctx);
// Handle `/* comment */);`
if !has_comment_before_right_paren || !p.print_expr_comments(self.span.end - 1) {
p.print_soft_newline();
}
p.dedent();
} else {
p.print_list(&self.arguments, ctx);
}
p.print_ascii_byte(b')');
p.print_arguments(self.span, &self.arguments, ctx);
p.add_source_mapping_end(self.span);
});
}
Expand Down Expand Up @@ -2167,7 +2139,7 @@ impl GenExpr for ChainExpression<'_> {
impl GenExpr for NewExpression<'_> {
fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
let mut wrap = precedence >= self.precedence();
let pure = self.pure && p.print_annotation_comment;
let pure = self.pure && p.options.print_annotation_comment();
if precedence >= Precedence::Postfix && pure {
wrap = true;
}
Expand All @@ -2184,22 +2156,7 @@ impl GenExpr for NewExpression<'_> {
// Omit the "()" when minifying, but only when safe to do so
if !p.options.minify || !self.arguments.is_empty() || precedence >= Precedence::Postfix
{
p.print_ascii_byte(b'(');
let (has_comment, has_comment_before_right_paren) = p
.contains_comment_in_call_like_expression(self.span, self.arguments.as_slice());
if has_comment {
p.indent();
p.print_list_with_comments(self.arguments.as_slice(), ctx);
// Handle `/* comment */);`
if !has_comment_before_right_paren || !p.print_expr_comments(self.span.end - 1)
{
p.print_soft_newline();
}
p.dedent();
} else {
p.print_list(&self.arguments, ctx);
}
p.print_ascii_byte(b')');
p.print_arguments(self.span, &self.arguments, ctx);
}
});
}
Expand Down Expand Up @@ -3624,13 +3581,7 @@ impl Gen for TSModuleBlock<'_> {
fn r#gen(&self, p: &mut Codegen, ctx: Context) {
let is_empty = self.directives.is_empty() && self.body.is_empty();
p.print_curly_braces(self.span, is_empty, |p| {
for directive in &self.directives {
directive.print(p, ctx);
}
for stmt in &self.body {
p.print_semicolon_if_needed();
stmt.print(p, ctx);
}
p.print_directives_and_statements(&self.directives, &self.body, ctx);
});
p.needs_semicolon = false;
}
Expand Down Expand Up @@ -3809,21 +3760,7 @@ impl GenExpr for V8IntrinsicExpression<'_> {
p.add_source_mapping(self.span);
p.print_ascii_byte(b'%');
self.name.print(p, Context::empty());
p.print_ascii_byte(b'(');
let (has_comment, has_comment_before_right_paren) =
p.contains_comment_in_call_like_expression(self.span, self.arguments.as_slice());
if has_comment {
p.indent();
p.print_list_with_comments(self.arguments.as_slice(), ctx);
// Handle `/* comment */);`
if !has_comment_before_right_paren || !p.print_expr_comments(self.span.end - 1) {
p.print_soft_newline();
}
p.dedent();
} else {
p.print_list(&self.arguments, ctx);
}
p.print_ascii_byte(b')');
p.print_arguments(self.span, &self.arguments, ctx);
p.add_source_mapping_end(self.span);
});
}
Expand Down
Loading
Loading