Skip to content
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
18 changes: 17 additions & 1 deletion crates/oxc_formatter/src/ast_nodes/generated/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use oxc_span::GetSpan;

use crate::{
ast_nodes::AstNode,
formatter::{Format, Formatter},
formatter::{
Format, Formatter,
trivia::{format_leading_comments, format_trailing_comments},
},
parentheses::NeedsParentheses,
print::{FormatFunctionOptions, FormatJsArrowFunctionExpressionOptions, FormatWrite},
utils::{suppressed::FormatSuppressedNode, typecast::format_type_cast_comment_node},
Expand Down Expand Up @@ -1582,6 +1585,19 @@ impl<'a> Format<'a> for AstNode<'a, ParenthesizedExpression<'a>> {
impl<'a> Format<'a> for AstNode<'a, Statement<'a>> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_, 'a>) {
if !matches!(self.inner, Statement::ExpressionStatement(_))
&& f.comments().has_trailing_suppression_comment(self.span().end)
{
format_leading_comments(self.span()).fmt(f);
FormatSuppressedNode(self.span()).fmt(f);
format_trailing_comments(
self.parent.span(),
self.inner.span(),
self.following_span_start,
)
.fmt(f);
return;
}
let allocator = self.allocator;
let parent = self.parent;
match self.inner {
Expand Down
11 changes: 11 additions & 0 deletions crates/oxc_formatter/src/formatter/comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,17 @@ impl<'a> Comments<'a> {
self.comments_before(start).iter().any(|comment| self.is_suppression_comment(comment))
}

/// Checks if there is a trailing suppression comment on the same line.
///
/// This supports patterns like:
/// `statement(); // prettier-ignore`
/// `statement(); /* prettier-ignore */`
pub fn has_trailing_suppression_comment(&self, pos: u32) -> bool {
self.end_of_line_comments_after(pos)
.iter()
.any(|comment| self.is_suppression_comment(comment))
}

/// Checks if a comment is a suppression comment (`oxfmt-ignore`).
///
/// `prettier-ignore` is also supported for compatibility.
Expand Down
9 changes: 9 additions & 0 deletions crates/oxc_formatter/src/print/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ use crate::{
object::{format_property_key, should_preserve_quote},
statement_body::FormatStatementBody,
string::{FormatLiteralStringToken, StringLiteralParentKind},
suppressed::FormatSuppressedNode,
tailwindcss::{tailwind_context_for_string_literal, write_tailwind_string_literal},
},
write,
Expand Down Expand Up @@ -556,13 +557,21 @@ fn expression_statement_needs_semicolon<'a>(

impl<'a> FormatWrite<'a> for AstNode<'a, ExpressionStatement<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) {
let span = self.span();
// Check if we need a leading semicolon to prevent ASI issues
if f.options().semicolons == Semicolons::AsNeeded
&& expression_statement_needs_semicolon(self, f)
{
write!(f, ";");
}

if f.comments().has_trailing_suppression_comment(span.end) {
// Preserve original text when the statement has an inline suppression comment:
// `stmt(); // prettier-ignore` or `stmt(); /* prettier-ignore */`
write!(f, [FormatSuppressedNode(span)]);
return;
}

write!(f, [self.expression(), OptionalSemicolon]);
}
}
Expand Down
10 changes: 8 additions & 2 deletions crates/oxc_formatter/src/utils/statement_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use crate::{
formatter::{
Buffer, Format, Formatter,
prelude::{format_once, soft_line_indent_or_space, space},
trivia::FormatTrailingComments,
trivia::{FormatTrailingComments, format_leading_comments},
},
print::FormatWrite,
utils::format_node_without_trailing_comments::FormatNodeWithoutTrailingComments,
utils::suppressed::FormatSuppressedNode,
write,
};

Expand Down Expand Up @@ -72,7 +73,12 @@ impl<'a> Format<'a> for FormatStatementBody<'a, '_> {
if if_stmt.consequent.span() == body_span && if_stmt.alternate.is_some()
);
if is_consequent_of_if_statement_parent {
write!(f, FormatNodeWithoutTrailingComments(self.body));
if f.context().comments().has_trailing_suppression_comment(body_span.end) {
write!(f, format_leading_comments(body_span));
write!(f, FormatSuppressedNode(body_span));
} else {
write!(f, FormatNodeWithoutTrailingComments(self.body));
}
let comments =
f.context().comments().end_of_line_comments_after(body_span.end);
FormatTrailingComments::Comments(comments).fmt(f);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,18 @@ Object.defineProperties ( exports , {
c +
b +
d
)
)

logger({ level: 'debug', message: `Really long debugging message about how ${user} called a certain part of our application with a certain ${payload}` }); // prettier-ignore

if (ok) logger( payload ); // prettier-ignore
else done();

if (a) step();
else if (b) logger( payload ); // prettier-ignore
else if (c) return {x:1,y:2}; // oxfmt-ignore
else done();

logger( payload ); /* prettier-ignore */
if (ok) return {a:1,b:2}; /* oxfmt-ignore */
else done();
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ Object.defineProperties ( exports , {
b +
d
)

logger({ level: 'debug', message: `Really long debugging message about how ${user} called a certain part of our application with a certain ${payload}` }); // prettier-ignore

if (ok) logger( payload ); // prettier-ignore
else done();

if (a) step();
else if (b) logger( payload ); // prettier-ignore
else if (c) return {x:1,y:2}; // oxfmt-ignore
else done();

logger( payload ); /* prettier-ignore */
if (ok) return {a:1,b:2}; /* oxfmt-ignore */
else done();

==================== Output ====================
------------------
{ printWidth: 80 }
Expand All @@ -27,6 +42,23 @@ Object.defineProperties ( exports , {
d
)

logger({ level: 'debug', message: `Really long debugging message about how ${user} called a certain part of our application with a certain ${payload}` }); // prettier-ignore

if (ok)
logger( payload ); // prettier-ignore
else done();

if (a) step();
else if (b)
logger( payload ); // prettier-ignore
else if (c)
return {x:1,y:2}; // oxfmt-ignore
else done();

logger( payload ); /* prettier-ignore */
if (ok) return {a:1,b:2}; /* oxfmt-ignore */
else done();

-------------------
{ printWidth: 100 }
-------------------
Expand All @@ -41,4 +73,21 @@ Object.defineProperties ( exports , {
d
)

logger({ level: 'debug', message: `Really long debugging message about how ${user} called a certain part of our application with a certain ${payload}` }); // prettier-ignore

if (ok)
logger( payload ); // prettier-ignore
else done();

if (a) step();
else if (b)
logger( payload ); // prettier-ignore
else if (c)
return {x:1,y:2}; // oxfmt-ignore
else done();

logger( payload ); /* prettier-ignore */
if (ok) return {a:1,b:2}; /* oxfmt-ignore */
else done();

===================== End =====================
35 changes: 35 additions & 0 deletions crates/oxc_formatter/tests/fixtures/js/ignore/oxfmt.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,38 @@ const response = {
'_text': 'Turn on the lights',
intent: 'lights',
};

import {foo as bar} from "pkg"; // prettier-ignore
export const item={ a:1,b:2}; // prettier-ignore

const config={ retries:10,timeout:5000}; // prettier-ignore
let data=[ 1,2,3 ]; // prettier-ignore

function demo() {
return {a:1,b:2}; // prettier-ignore
}

function fail() {
throw new Error( "boom" ); // prettier-ignore
}

if (ok) logger( payload ); // prettier-ignore
while (keepGoing) tick( value ); // prettier-ignore

label : for ( ; ; ) { break label; } // prettier-ignore
for (let i=0;i<3;i++) step( i ); // prettier-ignore
for (const k in obj) use( k ); // prettier-ignore
for (const v of arr) use( v ); // prettier-ignore
while (ok) run( x ); // prettier-ignore
do run( x ); while (ok); // prettier-ignore
switch (kind) {case 1: act( ); break;} // prettier-ignore
try { a( ); } catch (e) { b( ); } // prettier-ignore
with (ctx) run( x ); // prettier-ignore

function f() {
return {a:1}; // oxfmt-ignore
}

function g() {
throw new Error( "boom" ); // oxfmt-ignore
}
109 changes: 107 additions & 2 deletions crates/oxc_formatter/tests/fixtures/js/ignore/oxfmt.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,41 @@ const response = {
intent: 'lights',
};

import {foo as bar} from "pkg"; // prettier-ignore
export const item={ a:1,b:2}; // prettier-ignore

const config={ retries:10,timeout:5000}; // prettier-ignore
let data=[ 1,2,3 ]; // prettier-ignore

function demo() {
return {a:1,b:2}; // prettier-ignore
}

function fail() {
throw new Error( "boom" ); // prettier-ignore
}

if (ok) logger( payload ); // prettier-ignore
while (keepGoing) tick( value ); // prettier-ignore

label : for ( ; ; ) { break label; } // prettier-ignore
for (let i=0;i<3;i++) step( i ); // prettier-ignore
for (const k in obj) use( k ); // prettier-ignore
for (const v of arr) use( v ); // prettier-ignore
while (ok) run( x ); // prettier-ignore
do run( x ); while (ok); // prettier-ignore
switch (kind) {case 1: act( ); break;} // prettier-ignore
try { a( ); } catch (e) { b( ); } // prettier-ignore
with (ctx) run( x ); // prettier-ignore

function f() {
return {a:1}; // oxfmt-ignore
}

function g() {
throw new Error( "boom" ); // oxfmt-ignore
}

==================== Output ====================
------------------
{ printWidth: 80 }
Expand Down Expand Up @@ -95,7 +130,7 @@ function a() {
};

function giveMeSome() {
a(a); // oxfmt-ignore
a( a ); // oxfmt-ignore
// shouldn't I return something? :shrug:
}

Expand Down Expand Up @@ -128,6 +163,41 @@ const response = {
intent: "lights",
};

import {foo as bar} from "pkg"; // prettier-ignore
export const item={ a:1,b:2}; // prettier-ignore

const config={ retries:10,timeout:5000}; // prettier-ignore
let data=[ 1,2,3 ]; // prettier-ignore

function demo() {
return {a:1,b:2}; // prettier-ignore
}

function fail() {
throw new Error( "boom" ); // prettier-ignore
}

if (ok) logger( payload ); // prettier-ignore
while (keepGoing) tick( value ); // prettier-ignore

label : for ( ; ; ) { break label; } // prettier-ignore
for (let i=0;i<3;i++) step( i ); // prettier-ignore
for (const k in obj) use( k ); // prettier-ignore
for (const v of arr) use( v ); // prettier-ignore
while (ok) run( x ); // prettier-ignore
do run( x ); while (ok); // prettier-ignore
switch (kind) {case 1: act( ); break;} // prettier-ignore
try { a( ); } catch (e) { b( ); } // prettier-ignore
with (ctx) run( x ); // prettier-ignore

function f() {
return {a:1}; // oxfmt-ignore
}

function g() {
throw new Error( "boom" ); // oxfmt-ignore
}

-------------------
{ printWidth: 100 }
-------------------
Expand Down Expand Up @@ -159,7 +229,7 @@ function a() {
};

function giveMeSome() {
a(a); // oxfmt-ignore
a( a ); // oxfmt-ignore
// shouldn't I return something? :shrug:
}

Expand Down Expand Up @@ -192,4 +262,39 @@ const response = {
intent: "lights",
};

import {foo as bar} from "pkg"; // prettier-ignore
export const item={ a:1,b:2}; // prettier-ignore

const config={ retries:10,timeout:5000}; // prettier-ignore
let data=[ 1,2,3 ]; // prettier-ignore

function demo() {
return {a:1,b:2}; // prettier-ignore
}

function fail() {
throw new Error( "boom" ); // prettier-ignore
}

if (ok) logger( payload ); // prettier-ignore
while (keepGoing) tick( value ); // prettier-ignore

label : for ( ; ; ) { break label; } // prettier-ignore
for (let i=0;i<3;i++) step( i ); // prettier-ignore
for (const k in obj) use( k ); // prettier-ignore
for (const v of arr) use( v ); // prettier-ignore
while (ok) run( x ); // prettier-ignore
do run( x ); while (ok); // prettier-ignore
switch (kind) {case 1: act( ); break;} // prettier-ignore
try { a( ); } catch (e) { b( ); } // prettier-ignore
with (ctx) run( x ); // prettier-ignore

function f() {
return {a:1}; // oxfmt-ignore
}

function g() {
throw new Error( "boom" ); // oxfmt-ignore
}

===================== End =====================
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,12 @@ const a = 1
;(function() {
const b = 2;
})()

foo();
[1,2,3]; // prettier-ignore

bar();
[4,5,6]; // oxfmt-ignore

baz();
[7,8,9]
Loading
Loading