diff --git a/crates/oxc_language_server/src/linter/server_linter.rs b/crates/oxc_language_server/src/linter/server_linter.rs index 8e984e4c3f34f..8e7127ee3ceae 100644 --- a/crates/oxc_language_server/src/linter/server_linter.rs +++ b/crates/oxc_language_server/src/linter/server_linter.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::{Component, Path, PathBuf}; use std::sync::Arc; use globset::Glob; @@ -28,8 +28,8 @@ impl ServerLinter { let nested_configs = Self::create_nested_configs(root_uri, options); let root_path = root_uri.to_file_path().unwrap(); let relative_config_path = options.config_path.clone(); - let oxlintrc = if relative_config_path.is_some() { - let config = root_path.join(relative_config_path.unwrap()); + let oxlintrc = if let Some(relative_config_path) = relative_config_path { + let config = normalize_path(root_path.join(relative_config_path)); if config.try_exists().is_ok_and(|exists| exists) { if let Ok(oxlintrc) = Oxlintrc::from_file(&config) { oxlintrc @@ -206,19 +206,55 @@ impl ServerLinter { } } +/// Normalize a path by removing `.` and resolving `..` components, +/// without touching the filesystem. +pub fn normalize_path>(path: P) -> PathBuf { + let mut result = PathBuf::new(); + + for component in path.as_ref().components() { + match component { + Component::ParentDir => { + result.pop(); + } + Component::CurDir => { + // Skip current directory component + } + Component::Normal(c) => { + result.push(c); + } + Component::RootDir | Component::Prefix(_) => { + result.push(component.as_os_str()); + } + } + } + + result +} + #[cfg(test)] mod test { - use std::{path::PathBuf, str::FromStr}; + use std::{ + path::{Path, PathBuf}, + str::FromStr, + }; use rustc_hash::FxHashMap; use tower_lsp_server::lsp_types::Uri; use crate::{ Options, - linter::server_linter::ServerLinter, + linter::server_linter::{ServerLinter, normalize_path}, tester::{Tester, get_file_uri}, }; + #[test] + fn test_normalize_path() { + assert_eq!( + normalize_path(Path::new("/root/directory/./.oxlintrc.json")), + Path::new("/root/directory/.oxlintrc.json") + ); + } + #[test] fn test_create_nested_configs_with_disabled_nested_configs() { let mut flags = FxHashMap::default();