Skip to content

Commit 8d30bce

Browse files
committed
refactor(linter/tsgolint): report an error if the tsgolint exe could not be found (#13590)
Fixes #13399
1 parent 8314ed5 commit 8d30bce

File tree

2 files changed

+46
-17
lines changed

2 files changed

+46
-17
lines changed

apps/oxlint/src/lint.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,16 @@ impl LintRunner {
308308
// Run type-aware linting through tsgolint
309309
// TODO: Add a warning message if `tsgolint` cannot be found, but type-aware rules are enabled
310310
if self.options.type_aware {
311-
if let Err(err) = TsGoLintState::new(options.cwd(), config_store.clone())
312-
.with_silent(misc_options.silent)
313-
.lint(&files_to_lint, tx_error.clone())
311+
let state = match TsGoLintState::try_new(options.cwd(), config_store.clone()) {
312+
Ok(state) => state,
313+
Err(err) => {
314+
print_and_flush_stdout(stdout, &err);
315+
return CliRunResult::TsGoLintError;
316+
}
317+
};
318+
319+
if let Err(err) =
320+
state.with_silent(misc_options.silent).lint(&files_to_lint, tx_error.clone())
314321
{
315322
print_and_flush_stdout(stdout, &err);
316323
return CliRunResult::TsGoLintError;

crates/oxc_linter/src/tsgolint.rs

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,20 @@ pub struct TsGoLintState {
3535

3636
impl TsGoLintState {
3737
pub fn new(cwd: &Path, config_store: ConfigStore) -> Self {
38-
TsGoLintState {
39-
config_store,
40-
executable_path: try_find_tsgolint_executable(cwd).unwrap_or(PathBuf::from("tsgolint")),
41-
cwd: cwd.to_path_buf(),
42-
silent: false,
43-
}
38+
let executable_path =
39+
try_find_tsgolint_executable(cwd).unwrap_or(PathBuf::from("tsgolint"));
40+
41+
TsGoLintState { config_store, executable_path, cwd: cwd.to_path_buf(), silent: false }
42+
}
43+
44+
/// Try to create a new TsGoLintState, returning an error if the executable cannot be found.
45+
///
46+
/// # Errors
47+
/// Returns an error if the tsgolint executable cannot be found.
48+
pub fn try_new(cwd: &Path, config_store: ConfigStore) -> Result<Self, String> {
49+
let executable_path = try_find_tsgolint_executable(cwd)?;
50+
51+
Ok(TsGoLintState { config_store, executable_path, cwd: cwd.to_path_buf(), silent: false })
4452
}
4553

4654
/// Set to `true` to skip file system reads.
@@ -710,15 +718,29 @@ fn parse_single_message(
710718
/// Tries to find the `tsgolint` executable. In priority order, this will check:
711719
/// 1. The `OXLINT_TSGOLINT_PATH` environment variable.
712720
/// 2. The `tsgolint` binary in the current working directory's `node_modules/.bin` directory.
713-
pub fn try_find_tsgolint_executable(cwd: &Path) -> Option<PathBuf> {
721+
///
722+
/// # Errors
723+
/// Returns an error if `OXLINT_TSGOLINT_PATH` is set but does not exist or is not a file.
724+
/// Returns an error if the tsgolint executable could not be resolve inside `node_modules/.bin`.
725+
pub fn try_find_tsgolint_executable(cwd: &Path) -> Result<PathBuf, String> {
714726
// Check the environment variable first
715-
if let Ok(path) = std::env::var("OXLINT_TSGOLINT_PATH") {
716-
let path = PathBuf::from(path);
727+
if let Ok(path_str) = std::env::var("OXLINT_TSGOLINT_PATH") {
728+
let path = PathBuf::from(&path_str);
717729
if path.is_dir() {
718-
return Some(path.join("tsgolint"));
719-
} else if path.is_file() {
720-
return Some(path);
730+
let tsgolint_path = path.join("tsgolint");
731+
if tsgolint_path.exists() {
732+
return Ok(tsgolint_path);
733+
}
734+
return Err(format!(
735+
"Failed to find tsgolint executable: OXLINT_TSGOLINT_PATH points to directory '{path_str}' but 'tsgolint' binary not found inside"
736+
));
737+
}
738+
if path.is_file() {
739+
return Ok(path);
721740
}
741+
return Err(format!(
742+
"Failed to find tsgolint executable: OXLINT_TSGOLINT_PATH points to '{path_str}' which does not exist"
743+
));
722744
}
723745

724746
// executing a sub command in windows, needs a `cmd` or `ps1` extension.
@@ -730,7 +752,7 @@ pub fn try_find_tsgolint_executable(cwd: &Path) -> Option<PathBuf> {
730752
loop {
731753
let node_modules_bin = current_dir.join("node_modules").join(".bin").join(file);
732754
if node_modules_bin.exists() {
733-
return Some(node_modules_bin);
755+
return Ok(node_modules_bin);
734756
}
735757

736758
// If we reach the root directory, stop searching
@@ -739,7 +761,7 @@ pub fn try_find_tsgolint_executable(cwd: &Path) -> Option<PathBuf> {
739761
}
740762
}
741763

742-
None
764+
Err("Failed to find tsgolint executable".to_string())
743765
}
744766

745767
#[cfg(test)]

0 commit comments

Comments
 (0)