Skip to content

Commit

Permalink
refactor(codegen): simplify printing annotation comments (#6027)
Browse files Browse the repository at this point in the history
Simplify printing annotation comments, reusing the architecture of printing JSDoc.
  • Loading branch information
Dunqing committed Sep 25, 2024
1 parent f866781 commit fe696f0
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 278 deletions.
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

0 comments on commit fe696f0

Please sign in to comment.