@@ -16,17 +16,24 @@ pub fn run(args: &[String], verbose: u8) -> Result<i32> {
1616 eprintln ! ( "Running: prettier {}" , args. join( " " ) ) ;
1717 }
1818
19- runner:: run_filtered (
19+ // Prettier >= 1.19 logs its `--check` results ("[warn] <file>") to stderr,
20+ // not stdout — the filter must see the combined output, and the exit code,
21+ // to avoid reporting a failing check as success.
22+ runner:: run_filtered_with_exit (
2023 cmd,
2124 "prettier" ,
2225 & args. join ( " " ) ,
23- filter_prettier_output ,
24- RunOptions :: stdout_only ( ) ,
26+ filter_prettier_output_with_exit ,
27+ RunOptions :: default ( ) ,
2528 )
2629}
2730
2831/// Filter Prettier output - show only files that need formatting
2932pub fn filter_prettier_output ( output : & str ) -> String {
33+ filter_prettier_output_with_exit ( output, 0 )
34+ }
35+
36+ fn filter_prettier_output_with_exit ( output : & str , exit_code : i32 ) -> String {
3037 // #221: empty or whitespace-only output means prettier didn't run
3138 if output. trim ( ) . is_empty ( ) {
3239 return "Error: prettier produced no output" . to_string ( ) ;
@@ -39,6 +46,13 @@ pub fn filter_prettier_output(output: &str) -> String {
3946 for line in output. lines ( ) {
4047 let trimmed = line. trim ( ) ;
4148
49+ // Prettier >= 1.19 prefixes each check result with "[warn] " (on
50+ // stderr). Strip the prefix so those file lines are recognized.
51+ let trimmed = trimmed
52+ . strip_prefix ( "[warn]" )
53+ . map ( str:: trim_start)
54+ . unwrap_or ( trimmed) ;
55+
4256 // Detect check mode vs write mode
4357 if trimmed. contains ( "Checking formatting" ) {
4458 is_check_mode = true ;
@@ -49,7 +63,6 @@ pub fn filter_prettier_output(output: &str) -> String {
4963 && !trimmed. starts_with ( "Checking" )
5064 && !trimmed. starts_with ( "All matched" )
5165 && !trimmed. starts_with ( "Code style" )
52- && !trimmed. contains ( "[warn]" )
5366 && !trimmed. contains ( "[error]" )
5467 && ( trimmed. ends_with ( ".ts" )
5568 || trimmed. ends_with ( ".tsx" )
@@ -88,6 +101,12 @@ pub fn filter_prettier_output(output: &str) -> String {
88101 if is_check_mode {
89102 // Check mode: show files that need formatting
90103 if files_to_format. is_empty ( ) {
104+ if exit_code != 0 {
105+ // Prettier failed but no file list could be parsed (unknown
106+ // extension, unexpected output shape). Never claim success on
107+ // a failing check — pass the real output through.
108+ return output. trim ( ) . to_string ( ) ;
109+ }
91110 result. push_str ( "Prettier: All files formatted correctly\n " ) ;
92111 } else {
93112 result. push_str ( & format ! (
@@ -181,4 +200,47 @@ Code style issues found in the above file(s). Forgot to run Prettier?
181200 assert ! ( result. contains( "Error" ) ) ;
182201 assert ! ( !result. contains( "All files formatted" ) ) ;
183202 }
203+
204+ // --- failing `--check` writes "[warn] <file>" to stderr (prettier >= 1.19) ---
205+
206+ #[ test]
207+ fn test_filter_check_failure_warn_prefixed_files ( ) {
208+ // Real prettier 3.x --check output (combined stdout + stderr)
209+ let output = "Checking formatting...\n \
210+ [warn] src/app.ts\n \
211+ [warn] src/util.js\n \
212+ [warn] Code style issues found in the above files. Run Prettier with --write to fix.";
213+ let result = filter_prettier_output_with_exit ( output, 1 ) ;
214+ assert ! (
215+ result. contains( "2 files need formatting" ) ,
216+ "got: {}" ,
217+ result
218+ ) ;
219+ assert ! ( result. contains( "src/app.ts" ) ) ;
220+ assert ! ( result. contains( "src/util.js" ) ) ;
221+ assert ! ( !result. contains( "All files formatted correctly" ) ) ;
222+ }
223+
224+ #[ test]
225+ fn test_filter_check_failure_never_reports_success ( ) {
226+ // Unrecognized extension: no file list parsed, but prettier exited 1 —
227+ // must not claim success.
228+ let output = "Checking formatting...\n \
229+ [warn] src/component.vue\n \
230+ [warn] Code style issues found in the above file. Run Prettier with --write to fix.";
231+ let result = filter_prettier_output_with_exit ( output, 1 ) ;
232+ assert ! (
233+ !result. contains( "All files formatted correctly" ) ,
234+ "failing check reported as success: {}" ,
235+ result
236+ ) ;
237+ assert ! ( result. contains( "src/component.vue" ) ) ;
238+ }
239+
240+ #[ test]
241+ fn test_filter_check_success_exit_zero_unchanged ( ) {
242+ let output = "Checking formatting...\n All matched files use Prettier code style!" ;
243+ let result = filter_prettier_output_with_exit ( output, 0 ) ;
244+ assert ! ( result. contains( "All files formatted correctly" ) ) ;
245+ }
184246}
0 commit comments