Skip to content

Commit 9731c56

Browse files
committed
refactor(oxlint): move output from CliRunResult::InvalidOption to outside and use more Enums for different invalid options (#8778)
Now we can choose which exit code to use for a specific (unexpected) result
1 parent fe45bee commit 9731c56

File tree

4 files changed

+69
-52
lines changed

4 files changed

+69
-52
lines changed

apps/oxlint/src/lint.rs

+41-30
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,12 @@ impl Runner for LintRunner {
8686

8787
let filter = match Self::get_filters(filter) {
8888
Ok(filter) => filter,
89-
Err(e) => return e,
89+
Err((result, message)) => {
90+
stdout.write_all(message.as_bytes()).or_else(Self::check_for_writer_error).unwrap();
91+
stdout.flush().unwrap();
92+
93+
return result;
94+
}
9095
};
9196

9297
let extensions = VALID_EXTENSIONS
@@ -99,7 +104,13 @@ impl Runner for LintRunner {
99104
Self::find_oxlint_config(&self.cwd, basic_options.config.as_ref());
100105

101106
if let Err(err) = config_search_result {
102-
return err;
107+
stdout
108+
.write_all(format!("Failed to parse configuration file.\n{err}\n").as_bytes())
109+
.or_else(Self::check_for_writer_error)
110+
.unwrap();
111+
stdout.flush().unwrap();
112+
113+
return CliRunResult::InvalidOptionConfig;
103114
}
104115

105116
let mut oxlintrc = config_search_result.unwrap();
@@ -178,9 +189,13 @@ impl Runner for LintRunner {
178189
let handler = GraphicalReportHandler::new();
179190
let mut err = String::new();
180191
handler.render_report(&mut err, &diagnostic).unwrap();
181-
return CliRunResult::InvalidOptions {
182-
message: format!("Failed to parse configuration file.\n{err}"),
183-
};
192+
stdout
193+
.write_all(format!("Failed to parse configuration file.\n{err}\n").as_bytes())
194+
.or_else(Self::check_for_writer_error)
195+
.unwrap();
196+
stdout.flush().unwrap();
197+
198+
return CliRunResult::InvalidOptionConfig;
184199
}
185200
};
186201

@@ -193,11 +208,12 @@ impl Runner for LintRunner {
193208
options = options.with_tsconfig(path);
194209
} else {
195210
let path = if path.is_relative() { options.cwd().join(path) } else { path.clone() };
196-
return CliRunResult::InvalidOptions {
197-
message: format!(
198-
"The tsconfig file {path:?} does not exist, Please provide a valid tsconfig file.",
199-
),
200-
};
211+
stdout.write_all(format!(
212+
"The tsconfig file {path:?} does not exist, Please provide a valid tsconfig file.\n",
213+
).as_bytes()).or_else(Self::check_for_writer_error).unwrap();
214+
stdout.flush().unwrap();
215+
216+
return CliRunResult::InvalidOptionTsConfig;
201217
}
202218
}
203219

@@ -262,7 +278,7 @@ impl LintRunner {
262278
// in one place.
263279
fn get_filters(
264280
filters_arg: Vec<(AllowWarnDeny, String)>,
265-
) -> Result<Vec<LintFilter>, CliRunResult> {
281+
) -> Result<Vec<LintFilter>, (CliRunResult, String)> {
266282
let mut filters = Vec::with_capacity(filters_arg.len());
267283

268284
for (severity, filter_arg) in filters_arg {
@@ -271,23 +287,22 @@ impl LintRunner {
271287
filters.push(filter);
272288
}
273289
Err(InvalidFilterKind::Empty) => {
274-
return Err(CliRunResult::InvalidOptions {
275-
message: format!("Cannot {severity} an empty filter."),
276-
});
290+
return Err((
291+
CliRunResult::InvalidOptionSeverityWithoutFilter,
292+
format!("Cannot {severity} an empty filter.\n"),
293+
));
277294
}
278295
Err(InvalidFilterKind::PluginMissing(filter)) => {
279-
return Err(CliRunResult::InvalidOptions {
280-
message: format!(
281-
"Failed to {severity} filter {filter}: Plugin name is missing. Expected <plugin>/<rule>"
296+
return Err((CliRunResult::InvalidOptionSeverityWithoutPluginName, format!(
297+
"Failed to {severity} filter {filter}: Plugin name is missing. Expected <plugin>/<rule>\n"
282298
),
283-
});
299+
));
284300
}
285301
Err(InvalidFilterKind::RuleMissing(filter)) => {
286-
return Err(CliRunResult::InvalidOptions {
287-
message: format!(
288-
"Failed to {severity} filter {filter}: Rule name is missing. Expected <plugin>/<rule>"
302+
return Err((CliRunResult::InvalidOptionSeverityWithoutRuleName, format!(
303+
"Failed to {severity} filter {filter}: Rule name is missing. Expected <plugin>/<rule>\n"
289304
),
290-
});
305+
));
291306
}
292307
}
293308
}
@@ -296,10 +311,10 @@ impl LintRunner {
296311
}
297312

298313
// finds the oxlint config
299-
// when config is provided, but not found, an CliRunResult is returned, else the oxlintrc config file is returned
314+
// when config is provided, but not found, an String with the formatted error is returned, else the oxlintrc config file is returned
300315
// when no config is provided, it will search for the default file names in the current working directory
301316
// when no file is found, the default configuration is returned
302-
fn find_oxlint_config(cwd: &Path, config: Option<&PathBuf>) -> Result<Oxlintrc, CliRunResult> {
317+
fn find_oxlint_config(cwd: &Path, config: Option<&PathBuf>) -> Result<Oxlintrc, String> {
303318
if let Some(config_path) = config {
304319
let full_path = cwd.join(config_path);
305320
return match Oxlintrc::from_file(&full_path) {
@@ -308,9 +323,7 @@ impl LintRunner {
308323
let handler = GraphicalReportHandler::new();
309324
let mut err = String::new();
310325
handler.render_report(&mut err, &diagnostic).unwrap();
311-
return Err(CliRunResult::InvalidOptions {
312-
message: format!("Failed to parse configuration file.\n{err}"),
313-
});
326+
return Err(err);
314327
}
315328
};
316329
}
@@ -568,9 +581,7 @@ mod test {
568581
Tester::new().test(&["--tsconfig", "fixtures/tsconfig/tsconfig.json"]);
569582

570583
// failed
571-
assert!(Tester::new()
572-
.get_invalid_option_result(&["--tsconfig", "oxc/tsconfig.json"])
573-
.contains("oxc/tsconfig.json\" does not exist, Please provide a valid tsconfig file."));
584+
Tester::new().test_and_snapshot(&["--tsconfig", "oxc/tsconfig.json"]);
574585
}
575586

576587
#[test]

apps/oxlint/src/result.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ use std::process::{ExitCode, Termination};
33
#[derive(Debug)]
44
pub enum CliRunResult {
55
None,
6-
InvalidOptions { message: String },
6+
InvalidOptionConfig,
7+
InvalidOptionTsConfig,
8+
InvalidOptionSeverityWithoutFilter,
9+
InvalidOptionSeverityWithoutPluginName,
10+
InvalidOptionSeverityWithoutRuleName,
711
LintSucceeded,
812
LintFoundErrors,
913
LintMaxWarningsExceeded,
@@ -27,11 +31,12 @@ impl Termination for CliRunResult {
2731
Self::ConfigFileInitFailed
2832
| Self::LintFoundErrors
2933
| Self::LintNoWarningsAllowed
30-
| Self::LintMaxWarningsExceeded => ExitCode::FAILURE,
31-
Self::InvalidOptions { message } => {
32-
println!("Invalid Options: {message}");
33-
ExitCode::FAILURE
34-
}
34+
| Self::LintMaxWarningsExceeded
35+
| Self::InvalidOptionConfig
36+
| Self::InvalidOptionTsConfig
37+
| Self::InvalidOptionSeverityWithoutFilter
38+
| Self::InvalidOptionSeverityWithoutPluginName
39+
| Self::InvalidOptionSeverityWithoutRuleName => ExitCode::FAILURE,
3540
}
3641
}
3742
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
source: apps/oxlint/src/tester.rs
3+
---
4+
##########
5+
arguments: --tsconfig oxc/tsconfig.json
6+
working directory:
7+
----------
8+
The tsconfig file "<cwd>/oxc/tsconfig.json" does not exist, Please provide a valid tsconfig file.

apps/oxlint/src/tester.rs

+9-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#[cfg(test)]
2-
use crate::cli::{lint_command, CliRunResult, LintRunner};
2+
use crate::cli::{lint_command, LintRunner};
33
#[cfg(test)]
44
use crate::runner::Runner;
55
#[cfg(test)]
@@ -38,28 +38,14 @@ impl Tester {
3838
let _ = LintRunner::new(options).with_cwd(self.cwd.clone()).run(&mut output);
3939
}
4040

41-
pub fn get_invalid_option_result(&self, args: &[&str]) -> String {
42-
let mut new_args = vec!["--silent"];
43-
new_args.extend(args);
44-
45-
let options = lint_command().run_inner(new_args.as_slice()).unwrap();
46-
let mut output = Vec::new();
47-
match LintRunner::new(options).with_cwd(self.cwd.clone()).run(&mut output) {
48-
CliRunResult::InvalidOptions { message } => message,
49-
other => {
50-
panic!("Expected InvalidOptions, got {other:?}");
51-
}
52-
}
53-
}
54-
5541
pub fn test_and_snapshot(&self, args: &[&str]) {
5642
self.test_and_snapshot_multiple(&[args]);
5743
}
5844

5945
pub fn test_and_snapshot_multiple(&self, multiple_args: &[&[&str]]) {
6046
let mut output: Vec<u8> = Vec::new();
6147
let current_cwd = std::env::current_dir().unwrap();
62-
let relative_dir = self.cwd.strip_prefix(current_cwd).unwrap_or(&self.cwd);
48+
let relative_dir = self.cwd.strip_prefix(&current_cwd).unwrap_or(&self.cwd);
6349

6450
for args in multiple_args {
6551
let options = lint_command().run_inner(*args).unwrap();
@@ -85,6 +71,13 @@ impl Tester {
8571
let output_string = &String::from_utf8(output).unwrap();
8672
let output_string = regex.replace_all(output_string, "<variable>ms");
8773

74+
// do not output the current working directory, each machine has a different one
75+
let cwd_string = current_cwd.to_str().unwrap();
76+
#[allow(clippy::disallowed_methods)]
77+
let cwd_string = cwd_string.replace('\\', "/");
78+
#[allow(clippy::disallowed_methods)]
79+
let output_string = output_string.replace(&cwd_string, "<cwd>");
80+
8881
let full_args_list =
8982
multiple_args.iter().map(|args| args.join(" ")).collect::<Vec<String>>().join(" ");
9083

0 commit comments

Comments
 (0)