mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
fix(parser): hashbang comment should not keep the end newline char (#5844)
Previously it included a newline in the value
```
"hashbang": {
"type": "Hashbang",
"start": 0,
"end": 16,
"value": "/usr/bin/node\n"
},
```
This change will also make the lexer emit a `\n` token, which will make comment position detection correct.
This commit is contained in:
parent
65a17346cd
commit
42dcadfccf
6 changed files with 29 additions and 8 deletions
|
|
@ -52,6 +52,7 @@ impl<'a> Gen for Hashbang<'a> {
|
|||
fn gen(&self, p: &mut Codegen, _ctx: Context) {
|
||||
p.print_str("#!");
|
||||
p.print_str(self.value.as_str());
|
||||
p.print_hard_newline();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -281,6 +281,11 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn print_hard_newline(&mut self) {
|
||||
self.print_char(b'\n');
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn print_semicolon(&mut self) {
|
||||
self.print_char(b';');
|
||||
|
|
|
|||
|
|
@ -176,10 +176,11 @@ impl<'a> Lexer<'a> {
|
|||
|
||||
/// Section 12.5 Hashbang Comments
|
||||
pub(super) fn read_hashbang_comment(&mut self) -> Kind {
|
||||
while let Some(c) = self.next_char().as_ref() {
|
||||
while let Some(c) = self.peek_char().as_ref() {
|
||||
if is_line_terminator(*c) {
|
||||
break;
|
||||
}
|
||||
self.consume_char();
|
||||
}
|
||||
self.token.is_on_new_line = true;
|
||||
Kind::HashbangComment
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ token
|
|||
kind: CommentKind::Block,
|
||||
position: CommentPosition::Leading,
|
||||
attached_to: 36,
|
||||
preceded_by_newline: false, // hashbang comment always end in newline
|
||||
preceded_by_newline: true,
|
||||
followed_by_newline: true,
|
||||
}];
|
||||
assert_eq!(comments, expected);
|
||||
|
|
|
|||
|
|
@ -523,6 +523,15 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hashbang() {
|
||||
let allocator = Allocator::default();
|
||||
let source_type = SourceType::default();
|
||||
let source = "#!/usr/bin/node\n;";
|
||||
let ret = Parser::new(&allocator, source, source_type).parse();
|
||||
assert_eq!(ret.program.hashbang.unwrap().value.as_str(), "/usr/bin/node");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unambiguous() {
|
||||
let allocator = Allocator::default();
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use cow_utils::CowUtils;
|
|||
use oxc_allocator::{Box, Vec};
|
||||
use oxc_ast::{ast::*, AstKind};
|
||||
use oxc_span::GetSpan;
|
||||
use oxc_syntax::identifier::is_identifier_name;
|
||||
use oxc_syntax::identifier::{is_identifier_name, is_line_terminator};
|
||||
|
||||
use self::{array::Array, object::ObjectLike, template_literal::TemplateLiteralPrinter};
|
||||
use crate::{
|
||||
|
|
@ -60,10 +60,6 @@ impl<'a> Format<'a> for Program<'a> {
|
|||
let mut parts = p.vec();
|
||||
if let Some(hashbang) = &self.hashbang {
|
||||
parts.push(hashbang.format(p));
|
||||
let c = p.source_text[..hashbang.span.end as usize].chars().last().unwrap();
|
||||
if p.is_next_line_empty_after_index(hashbang.span.end - c.len_utf8() as u32) {
|
||||
parts.extend(hardline!());
|
||||
}
|
||||
}
|
||||
if let Some(doc) = block::print_block_body(
|
||||
p,
|
||||
|
|
@ -81,7 +77,16 @@ impl<'a> Format<'a> for Program<'a> {
|
|||
|
||||
impl<'a> Format<'a> for Hashbang<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
Doc::Str(self.span.source_text(p.source_text))
|
||||
let mut parts = p.vec();
|
||||
parts.push(ss!(self.span.source_text(p.source_text)));
|
||||
parts.extend(hardline!());
|
||||
// Preserve original newline
|
||||
if let Some(c) = p.source_text[self.span.end as usize..].chars().nth(1) {
|
||||
if is_line_terminator(c) {
|
||||
parts.extend(hardline!());
|
||||
}
|
||||
}
|
||||
Doc::Array(parts)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue