Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(codegen): simplify printing annotation comments #6027

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
161 changes: 0 additions & 161 deletions crates/oxc_codegen/src/annotation_comment.rs

This file was deleted.

73 changes: 61 additions & 12 deletions crates/oxc_codegen/src/comment.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,41 @@
use daachorse::DoubleArrayAhoCorasick;
use once_cell::sync::Lazy;
use rustc_hash::FxHashMap;

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

use crate::Codegen;

pub static ANNOTATION_MATCHER: Lazy<DoubleArrayAhoCorasick<usize>> = Lazy::new(|| {
let patterns = vec!["#__NO_SIDE_EFFECTS__", "@__NO_SIDE_EFFECTS__", "@__PURE__", "#__PURE__"];

DoubleArrayAhoCorasick::new(patterns).unwrap()
});

pub type CommentsMap = FxHashMap</* attached_to */ u32, Vec<Comment>>;

impl<'a> Codegen<'a> {
pub(crate) fn build_leading_comments(&mut self, source_text: &str, trivias: &Trivias) {
let mut leading_comments: CommentsMap = FxHashMap::default();
for comment in trivias
.comments()
.copied()
.filter(|comment| Self::should_keep_comment(comment, source_text))
{
leading_comments.entry(comment.attached_to).or_default().push(comment);
pub fn preserve_annotate_comments(&self) -> bool {
self.comment_options.preserve_annotate_comments && !self.options.minify
}

pub(crate) fn build_comments(&mut self, trivias: &Trivias) {
for comment in trivias.comments().copied() {
self.comments.entry(comment.attached_to).or_default().push(comment);
}
self.leading_comments = leading_comments;
}

fn should_keep_comment(comment: &Comment, source_text: &str) -> bool {
comment.is_jsdoc(source_text)
pub fn has_annotation_comments(&self, start: u32) -> bool {
let Some(source_text) = self.source_text else { return false };
self.comments.get(&start).is_some_and(|comments| {
comments.iter().any(|comment| Self::is_annotation_comments(comment, source_text))
})
}

/// Weather to keep leading comments.
fn is_leading_comments(comment: &Comment, source_text: &str) -> bool {
(comment.is_jsdoc(source_text) || (comment.is_line() && Self::is_annotation_comments(comment, source_text)))
&& comment.preceded_by_newline
// webpack comment `/*****/`
&& !comment.span.source_text(source_text).chars().all(|c| c == '*')
Expand All @@ -32,7 +46,13 @@ impl<'a> Codegen<'a> {
return;
}
let Some(source_text) = self.source_text else { return };
let Some(comments) = self.leading_comments.remove(&start) else { return };
let Some(comments) = self.comments.remove(&start) else {
return;
};

let (comments, unused_comments): (Vec<_>, Vec<_>) = comments
.into_iter()
.partition(|comment| Self::is_leading_comments(comment, source_text));

if comments.first().is_some_and(|c| c.preceded_by_newline) {
// Skip printing newline if this comment is already on a newline.
Expand Down Expand Up @@ -73,5 +93,34 @@ impl<'a> Codegen<'a> {
self.print_hard_newline();
self.print_indent();
}

if !unused_comments.is_empty() {
self.comments.insert(start, unused_comments);
}
}

fn is_annotation_comments(comment: &Comment, source_text: &str) -> bool {
let comment_content = comment.span.source_text(source_text);
ANNOTATION_MATCHER.find_iter(comment_content).count() != 0
}

pub(crate) fn print_annotation_comments(&mut self, node_start: u32) {
if !self.preserve_annotate_comments() {
return;
}

// If there is has annotation comments awaiting move to here, print them.
let start = self.start_of_annotation_comment.take().unwrap_or(node_start);

let Some(source_text) = self.source_text else { return };
let Some(comments) = self.comments.remove(&start) else { return };

for comment in comments {
if !Self::is_annotation_comments(&comment, source_text) {
continue;
}
self.print_str(comment.real_span().source_text(source_text));
self.print_hard_space();
}
}
}
53 changes: 24 additions & 29 deletions crates/oxc_codegen/src/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use oxc_syntax::{
};

use crate::{
annotation_comment::AnnotationKind,
binary_expr_visitor::{BinaryExpressionVisitor, Binaryish, BinaryishOperator},
Codegen, Context, Operator,
};
Expand Down Expand Up @@ -559,19 +558,15 @@ impl<'a> Gen for VariableDeclaration<'a> {
p.print_str("declare ");
}

if p.comment_options.preserve_annotate_comments
if p.preserve_annotate_comments()
&& p.start_of_annotation_comment.is_none()
&& matches!(self.kind, VariableDeclarationKind::Const)
&& matches!(self.declarations.first(), Some(VariableDeclarator { init: Some(init), .. }) if init.is_function())
&& p.has_annotation_comments(self.span.start)
{
if let Some(declarator) = self.declarations.first() {
if let Some(ref init) = declarator.init {
let leading_annotate_comments =
p.get_leading_annotate_comments(self.span.start);
if !leading_annotate_comments.is_empty() {
p.move_comments(init.span().start, leading_annotate_comments);
}
}
}
p.start_of_annotation_comment = Some(self.span.start);
}

p.print_str(match self.kind {
VariableDeclarationKind::Const => "const",
VariableDeclarationKind::Let => "let",
Expand Down Expand Up @@ -604,6 +599,7 @@ impl<'a> Gen for VariableDeclarator<'a> {
p.print_soft_space();
p.print_equal();
p.print_soft_space();
p.print_annotation_comments(self.span.start);
init.print_expr(p, Precedence::Comma, ctx);
}
}
Expand All @@ -613,7 +609,7 @@ impl<'a> Gen for Function<'a> {
fn gen(&self, p: &mut Codegen, ctx: Context) {
let n = p.code_len();
let wrap = self.is_expression() && (p.start_of_stmt == n || p.start_of_default_export == n);
p.gen_comments(self.span.start);
p.print_annotation_comments(self.span.start);
p.wrap(wrap, |p| {
p.print_space_before_identifier();
p.add_source_mapping(self.span.start);
Expand Down Expand Up @@ -829,22 +825,18 @@ impl<'a> Gen for ExportNamedDeclaration<'a> {
p.add_source_mapping(self.span.start);
p.print_indent();

if p.comment_options.preserve_annotate_comments {
if p.preserve_annotate_comments() {
match &self.declaration {
Some(Declaration::FunctionDeclaration(_)) => {
p.gen_comments(self.span.start);
p.print_annotation_comments(self.span.start);
}
Some(Declaration::VariableDeclaration(var_decl))
if matches!(var_decl.kind, VariableDeclarationKind::Const) =>
{
if let Some(declarator) = var_decl.declarations.first() {
if let Some(ref init) = declarator.init {
let leading_annotate_comments =
p.get_leading_annotate_comments(self.span.start);
if !leading_annotate_comments.is_empty() {
p.move_comments(init.span().start, leading_annotate_comments);
}
}
if matches!(var_decl.declarations.first(), Some(VariableDeclarator { init: Some(init), .. }) if init.is_function())
&& p.has_annotation_comments(self.span.start)
{
p.start_of_annotation_comment = Some(self.span.start);
}
}
_ => {}
Expand Down Expand Up @@ -1374,13 +1366,17 @@ impl<'a> GenExpr for PrivateFieldExpression<'a> {

impl<'a> GenExpr for CallExpression<'a> {
fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
let is_export_default = p.start_of_default_export == p.code_len();
let mut wrap = precedence >= Precedence::New || ctx.intersects(Context::FORBID_CALL);
let annotate_comments = p.get_leading_annotate_comments(self.span.start);
if !annotate_comments.is_empty() && precedence >= Precedence::Postfix {
if p.has_annotation_comments(self.span.start) && precedence >= Precedence::Postfix {
wrap = true;
}

p.wrap(wrap, |p| {
p.print_comments(&annotate_comments, &mut AnnotationKind::empty());
p.print_annotation_comments(self.span.start);
if is_export_default {
p.start_of_default_export = p.code_len();
}
p.add_source_mapping(self.span.start);
self.callee.print_expr(p, Precedence::Postfix, Context::empty());
if self.optional {
Expand Down Expand Up @@ -1593,7 +1589,7 @@ impl<'a> Gen for PropertyKey<'a> {
impl<'a> GenExpr for ArrowFunctionExpression<'a> {
fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
p.wrap(precedence >= Precedence::Assign, |p| {
p.gen_comments(self.span.start);
p.print_annotation_comments(self.span.start);
if self.r#async {
p.add_source_mapping(self.span.start);
p.print_str("async");
Expand Down Expand Up @@ -2028,12 +2024,11 @@ impl<'a> GenExpr for ChainExpression<'a> {
impl<'a> GenExpr for NewExpression<'a> {
fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
let mut wrap = precedence >= self.precedence();
let annotate_comment = p.get_leading_annotate_comments(self.span.start);
if !annotate_comment.is_empty() && precedence >= Precedence::Postfix {
if p.has_annotation_comments(self.span.start) && precedence >= Precedence::Postfix {
wrap = true;
}
p.wrap(wrap, |p| {
p.print_comments(&annotate_comment, &mut AnnotationKind::empty());
p.print_annotation_comments(self.span.start);
p.print_space_before_identifier();
p.add_source_mapping(self.span.start);
p.print_str("new ");
Expand Down
Loading