mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(prettier): print leading comments with newlines (#1434)
This commit is contained in:
parent
2ba69f1f01
commit
0218ae8641
8 changed files with 76 additions and 34 deletions
|
|
@ -113,7 +113,7 @@ impl<'a, 'b> DisableDirectivesBuilder<'a, 'b> {
|
|||
// Get the span up to the next new line
|
||||
let stop = self.source_text[span.end as usize..]
|
||||
.lines()
|
||||
.take(if comment.is_single_line() { 1 } else { 2 })
|
||||
.take(2)
|
||||
.fold(span.end, |acc, line| acc + line.len() as u32);
|
||||
if text.trim().is_empty() {
|
||||
self.add_interval(span.end, stop, DisabledRule::All);
|
||||
|
|
|
|||
|
|
@ -45,9 +45,8 @@ expression: ban_ts_comment
|
|||
╭─[ban_ts_comment.tsx:2:1]
|
||||
2 │ if (false) {
|
||||
3 │ // @ts-expect-error: Unreachable code error
|
||||
· ──────────────────────────────────────────
|
||||
· ─────────────────────────────────────────
|
||||
4 │ console.log('hello');
|
||||
5 │ }
|
||||
╰────
|
||||
|
||||
⚠ Include a description after the @ts-expect-error directive to explain why the @ts-expect-error is necessary. The description must be 3 characters or longer.
|
||||
|
|
@ -123,9 +122,8 @@ expression: ban_ts_comment
|
|||
╭─[ban_ts_comment.tsx:2:1]
|
||||
2 │ if (false) {
|
||||
3 │ // @ts-ignore: Unreachable code error
|
||||
· ────────────────────────────────────
|
||||
· ───────────────────────────────────
|
||||
4 │ console.log('hello');
|
||||
5 │ }
|
||||
╰────
|
||||
|
||||
⚠ Include a description after the @ts-ignore directive to explain why the @ts-ignore is necessary. The description must be 3 characters or longer.
|
||||
|
|
@ -201,9 +199,8 @@ expression: ban_ts_comment
|
|||
╭─[ban_ts_comment.tsx:2:1]
|
||||
2 │ if (false) {
|
||||
3 │ // @ts-nocheck: Unreachable code error
|
||||
· ─────────────────────────────────────
|
||||
· ────────────────────────────────────
|
||||
4 │ console.log('hello');
|
||||
5 │ }
|
||||
╰────
|
||||
|
||||
⚠ Include a description after the @ts-nocheck directive to explain why the @ts-nocheck is necessary. The description must be 3 characters or longer.
|
||||
|
|
@ -267,9 +264,8 @@ expression: ban_ts_comment
|
|||
╭─[ban_ts_comment.tsx:2:1]
|
||||
2 │ if (false) {
|
||||
3 │ // @ts-check: Unreachable code error
|
||||
· ───────────────────────────────────
|
||||
· ──────────────────────────────────
|
||||
4 │ console.log('hello');
|
||||
5 │ }
|
||||
╰────
|
||||
|
||||
⚠ Include a description after the @ts-check directive to explain why the @ts-check is necessary. The description must be 3 characters or longer.
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
assertion_line: 105
|
||||
expression: no_abusive_eslint_disable
|
||||
---
|
||||
⚠ eslint-plugin-unicorn(no-abusive-eslint-disable): Unexpected `eslint-disable` comment that does not specify any rules to disable.
|
||||
╭─[no_abusive_eslint_disable.tsx:1:1]
|
||||
1 │
|
||||
2 │ // eslint-disable-next-line @scopewithoutplugin
|
||||
· ──────────────────────────────────────────────
|
||||
· ─────────────────────────────────────────────
|
||||
3 │ eval();
|
||||
4 │
|
||||
╰────
|
||||
help: Specify the rules you want to disable.
|
||||
|
||||
|
|
@ -24,7 +22,7 @@ expression: no_abusive_eslint_disable
|
|||
╭─[no_abusive_eslint_disable.tsx:2:1]
|
||||
2 │ foo();
|
||||
3 │ eval(); // eslint-disable-line
|
||||
· ─────────────────────
|
||||
· ────────────────────
|
||||
4 │
|
||||
╰────
|
||||
help: Specify the rules you want to disable.
|
||||
|
|
@ -58,9 +56,8 @@ expression: no_abusive_eslint_disable
|
|||
╭─[no_abusive_eslint_disable.tsx:1:1]
|
||||
1 │
|
||||
2 │ // eslint-disable-next-line
|
||||
· ──────────────────────────
|
||||
· ─────────────────────────
|
||||
3 │ eval();
|
||||
4 │
|
||||
╰────
|
||||
help: Specify the rules you want to disable.
|
||||
|
||||
|
|
|
|||
|
|
@ -104,9 +104,8 @@ expression: no_commented_out_tests
|
|||
╭─[no_commented_out_tests.tsx:1:1]
|
||||
1 │
|
||||
2 │ // test(
|
||||
· ───────
|
||||
· ──────
|
||||
3 │ // "foo", function () {}
|
||||
4 │ // )
|
||||
╰────
|
||||
help: Remove or uncomment this comment
|
||||
|
||||
|
|
|
|||
|
|
@ -375,14 +375,19 @@ impl<'a> Lexer<'a> {
|
|||
}
|
||||
|
||||
/// Section 12.4 Single Line Comment
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn skip_single_line_comment(&mut self) -> Kind {
|
||||
while let Some(c) = self.current.chars.next().as_ref() {
|
||||
if is_line_terminator(*c) {
|
||||
break;
|
||||
let start = self.current.token.start;
|
||||
while let Some(c) = self.current.chars.next() {
|
||||
if is_line_terminator(c) {
|
||||
self.current.token.is_on_new_line = true;
|
||||
self.trivia_builder
|
||||
.add_single_line_comment(start, self.offset() - c.len_utf8() as u32);
|
||||
return Kind::Comment;
|
||||
}
|
||||
}
|
||||
self.current.token.is_on_new_line = true;
|
||||
self.trivia_builder.add_single_line_comment(self.current.token.start, self.offset());
|
||||
// EOF
|
||||
self.trivia_builder.add_single_line_comment(start, self.offset());
|
||||
Kind::Comment
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#![allow(non_upper_case_globals)]
|
||||
|
||||
//! Comment helpers
|
||||
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
use oxc_ast::CommentKind;
|
||||
|
|
@ -9,7 +9,7 @@ use oxc_span::Span;
|
|||
|
||||
use crate::{
|
||||
doc::{Doc, Separator},
|
||||
hardline, indent, Prettier,
|
||||
hardline, indent, line, ss, Prettier,
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
|
|
@ -50,11 +50,28 @@ impl<'a> Prettier<'a> {
|
|||
while let Some((start, end, kind)) = self.trivias.peek().copied() {
|
||||
// Comment before the span
|
||||
if end <= range.start {
|
||||
self.trivias.next();
|
||||
|
||||
parts.push(self.print_comment(start, end, kind));
|
||||
if kind.is_multi_line() {
|
||||
let line_break = if self.has_newline(end) {
|
||||
if self.has_newline(start) {
|
||||
hardline!()
|
||||
} else {
|
||||
line!()
|
||||
}
|
||||
} else {
|
||||
ss!(" ")
|
||||
};
|
||||
parts.push(line_break);
|
||||
} else {
|
||||
parts.push(hardline!());
|
||||
}
|
||||
|
||||
let end = self.get_comment_end(kind, end);
|
||||
if self.skip_newline(self.skip_spaces(end)).is_some_and(|i| self.has_newline(i)) {
|
||||
parts.push(hardline!());
|
||||
}
|
||||
self.trivias.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
@ -96,4 +113,13 @@ impl<'a> Prettier<'a> {
|
|||
let comment = Span::new(start - 2, end + end_offset).source_text(self.source_text);
|
||||
Doc::Str(comment)
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn get_comment_end(&self, kind: CommentKind, end: u32) -> Option<u32> {
|
||||
if kind.is_single_line() {
|
||||
self.source_text[end as usize..].chars().next().map(|c| end + c.len_utf8() as u32)
|
||||
} else {
|
||||
Some(end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use std::{iter::Peekable, vec};
|
|||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::{ast::Program, AstKind, CommentKind, Trivias};
|
||||
use oxc_syntax::identifier::is_line_terminator;
|
||||
|
||||
use crate::{doc::Doc, format::Format, printer::Printer};
|
||||
|
||||
|
|
@ -107,4 +108,29 @@ impl<'a> Prettier<'a> {
|
|||
fn is_next_line_empty(&self, end: u32) -> bool {
|
||||
self.source_text[end as usize..].chars().nth(1).is_some_and(|c| c == '\n')
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn skip_newline(&self, start_index: Option<u32>) -> Option<u32> {
|
||||
let start_index = start_index?;
|
||||
let c = self.source_text[start_index as usize..].chars().next()?;
|
||||
is_line_terminator(c).then(|| start_index + c.len_utf8() as u32)
|
||||
}
|
||||
|
||||
fn skip_spaces(&self, start_index: Option<u32>) -> Option<u32> {
|
||||
let mut start_index = start_index?;
|
||||
for c in self.source_text[start_index as usize..].chars() {
|
||||
if matches!(c, ' ' | '\t') {
|
||||
start_index += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Some(start_index)
|
||||
}
|
||||
|
||||
fn has_newline(&self, start_index: u32) -> bool {
|
||||
let idx = self.skip_spaces(Some(start_index));
|
||||
let idx2 = self.skip_newline(idx);
|
||||
idx != idx2
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Compatibility: 115/771 (14.92%)
|
||||
Compatibility: 120/771 (15.56%)
|
||||
|
||||
# Failed
|
||||
|
||||
|
|
@ -99,7 +99,6 @@ Compatibility: 115/771 (14.92%)
|
|||
|
||||
### babel-plugins
|
||||
* babel-plugins/async-do-expressions.js
|
||||
* babel-plugins/async-generators.js
|
||||
* babel-plugins/bigint.js
|
||||
* babel-plugins/class-properties.js
|
||||
* babel-plugins/class-static-block.js
|
||||
|
|
@ -109,7 +108,6 @@ Compatibility: 115/771 (14.92%)
|
|||
* babel-plugins/deferred-import-evaluation.js
|
||||
* babel-plugins/destructuring-private.js
|
||||
* babel-plugins/do-expressions.js
|
||||
* babel-plugins/dynamic-import.js
|
||||
* babel-plugins/explicit-resource-management.js
|
||||
* babel-plugins/export-default-from.js
|
||||
* babel-plugins/export-namespace-from.js
|
||||
|
|
@ -121,7 +119,6 @@ Compatibility: 115/771 (14.92%)
|
|||
* babel-plugins/import-meta.js
|
||||
* babel-plugins/import-reflection.js
|
||||
* babel-plugins/jsx.js
|
||||
* babel-plugins/logical-assignment-operators.js
|
||||
* babel-plugins/module-blocks.js
|
||||
* babel-plugins/nullish-coalescing-operator.js
|
||||
* babel-plugins/numeric-separator.js
|
||||
|
|
@ -508,7 +505,6 @@ Compatibility: 115/771 (14.92%)
|
|||
### generator
|
||||
* generator/anonymous.js
|
||||
* generator/async.js
|
||||
* generator/function-name-starts-with-get.js
|
||||
|
||||
### identifier/for-of
|
||||
* identifier/for-of/let.js
|
||||
|
|
@ -636,9 +632,6 @@ Compatibility: 115/771 (14.92%)
|
|||
### nullish-coalescing
|
||||
* nullish-coalescing/nullish_coalesing_operator.js
|
||||
|
||||
### numeric-separators
|
||||
* numeric-separators/number.js
|
||||
|
||||
### object-prop-break-in
|
||||
* object-prop-break-in/comment.js
|
||||
* object-prop-break-in/short-keys.js
|
||||
|
|
|
|||
Loading…
Reference in a new issue