From 1380d8b5dc0475e3f4a56c876334a1c9a2522d2c Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Tue, 8 Oct 2024 05:42:41 +0000 Subject: [PATCH] fix(parser): should regard comments where after `=` as leading comments of next token (#6355) A part of fixing https://github.com/rolldown/rolldown/pull/2375/files#r1789011257 ### Compare to `Babel` This is also among its behavior, see image ### Compare to `esbuild` I haven't looked through related code from esbuild, from its playground, the behavior looks the same https://esbuild.github.io/try/#dAAwLjI0LjAAAGNvbnN0IEEgPSAvLyBzZGRkZGQKKCkgPT4ge30 --- crates/oxc_parser/src/lexer/mod.rs | 2 +- crates/oxc_parser/src/lexer/trivia_builder.rs | 53 +++++++++++++++++-- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/crates/oxc_parser/src/lexer/mod.rs b/crates/oxc_parser/src/lexer/mod.rs index 1961976df2033..1e11d5b619e5d 100644 --- a/crates/oxc_parser/src/lexer/mod.rs +++ b/crates/oxc_parser/src/lexer/mod.rs @@ -218,7 +218,7 @@ impl<'a> Lexer<'a> { self.token.end = self.offset(); debug_assert!(self.token.start <= self.token.end); let token = self.token; - self.trivia_builder.handle_token(token.start); + self.trivia_builder.handle_token(token); self.token = Token::default(); token } diff --git a/crates/oxc_parser/src/lexer/trivia_builder.rs b/crates/oxc_parser/src/lexer/trivia_builder.rs index 315f8c50035eb..4579dc2737f3a 100644 --- a/crates/oxc_parser/src/lexer/trivia_builder.rs +++ b/crates/oxc_parser/src/lexer/trivia_builder.rs @@ -1,6 +1,8 @@ use oxc_ast::{Comment, CommentKind, CommentPosition, Trivias}; use oxc_span::Span; +use super::{Kind, Token}; + #[derive(Debug)] pub struct TriviaBuilder { // This is a set of unique comments. Duplicated @@ -16,11 +18,20 @@ pub struct TriviaBuilder { /// Saw a newline before this position saw_newline: bool, + + /// Previous token kind, used to indicates comments are trailing from what kind + previous_kind: Kind, } impl Default for TriviaBuilder { fn default() -> Self { - Self { comments: vec![], irregular_whitespaces: vec![], processed: 0, saw_newline: true } + Self { + comments: vec![], + irregular_whitespaces: vec![], + processed: 0, + saw_newline: true, + previous_kind: Kind::Undetermined, + } } } @@ -57,13 +68,14 @@ impl TriviaBuilder { self.saw_newline = true; } - pub fn handle_token(&mut self, token_start: u32) { + pub fn handle_token(&mut self, token: Token) { let len = self.comments.len(); + self.previous_kind = token.kind; if self.processed < len { // All unprocessed preceding comments are leading comments attached to this token start. for comment in &mut self.comments[self.processed..] { comment.position = CommentPosition::Leading; - comment.attached_to = token_start; + comment.attached_to = token.start; } self.processed = len; } @@ -85,8 +97,8 @@ impl TriviaBuilder { if comment.is_line() { // A line comment is always followed by a newline. This is never set in `handle_newline`. comment.followed_by_newline = true; - // A line comment is trailing when it is no preceded by a newline. - if !self.saw_newline { + // A line comment is trailing when it is no preceded by a newline and it is not after `=` + if !self.saw_newline && self.previous_kind != Kind::Eq { self.processed = self.comments.len() + 1; // +1 to include this comment. } self.saw_newline = true; @@ -236,4 +248,35 @@ token /* Trailing 1 */ ]; assert_eq!(comments, expected); } + + #[test] + fn leading_comments_after_eq() { + let source_text = " + const v1 = // Leading comment 1 + foo(); + function foo(param =// Leading comment 2 + new Foo() + ) {} + "; + let comments = get_comments(source_text); + let expected = vec![ + Comment { + span: Span::new(26, 44), + kind: CommentKind::Line, + position: CommentPosition::Leading, + attached_to: 57, + preceded_by_newline: false, + followed_by_newline: true, + }, + Comment { + span: Span::new(98, 116), + kind: CommentKind::Line, + position: CommentPosition::Leading, + attached_to: 129, + preceded_by_newline: false, + followed_by_newline: true, + }, + ]; + assert_eq!(comments, expected); + } }