Skip to content

Commit 7dd438a

Browse files
committed
refactor(language_server): use LintRunner
1 parent b1c0f28 commit 7dd438a

File tree

5 files changed

+52
-131
lines changed

5 files changed

+52
-131
lines changed

crates/oxc_language_server/src/linter/isolated_lint_handler.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use tower_lsp_server::{UriExt, lsp_types::Uri};
1111
use oxc_allocator::Allocator;
1212
use oxc_linter::{
1313
AllowWarnDeny, ConfigStore, DirectivesStore, DisableDirectives, LINTABLE_EXTENSIONS,
14-
LintOptions, LintService, LintServiceOptions, Linter, Message, RuntimeFileSystem,
15-
create_unused_directives_diagnostics, read_to_arena_str, read_to_string,
14+
LintOptions, LintRunner, LintRunnerBuilder, LintServiceOptions, Linter, Message,
15+
RuntimeFileSystem, create_unused_directives_diagnostics, read_to_arena_str, read_to_string,
1616
};
1717

1818
use super::error_with_position::{
@@ -23,12 +23,13 @@ use super::error_with_position::{
2323
#[derive(Debug, Clone)]
2424
pub struct IsolatedLintHandlerOptions {
2525
pub use_cross_module: bool,
26+
pub type_aware: bool,
2627
pub root_path: PathBuf,
2728
pub tsconfig_path: Option<PathBuf>,
2829
}
2930

3031
pub struct IsolatedLintHandler {
31-
service: LintService,
32+
runner: LintRunner,
3233
directives_coordinator: DirectivesStore,
3334
unused_directives_severity: Option<AllowWarnDeny>,
3435
}
@@ -81,11 +82,11 @@ impl IsolatedLintHandler {
8182
lint_service_options = lint_service_options.with_tsconfig(tsconfig_path);
8283
}
8384

84-
let mut service = LintService::new(linter, lint_service_options);
85-
service.set_disable_directives_map(directives_coordinator.map());
86-
8785
Self {
88-
service,
86+
runner: LintRunnerBuilder::new(lint_service_options, linter)
87+
.with_type_aware(options.type_aware)
88+
.build()
89+
.unwrap(),
8990
directives_coordinator,
9091
unused_directives_severity: lint_options.report_unused_directive,
9192
}
@@ -113,14 +114,14 @@ impl IsolatedLintHandler {
113114
debug!("lint {}", path.display());
114115
let rope = &Rope::from_str(source_text);
115116

117+
let fs = Box::new(IsolatedLintHandlerFileSystem::new(
118+
path.to_path_buf(),
119+
Arc::from(source_text),
120+
));
121+
116122
let mut messages: Vec<DiagnosticReport> = self
117-
.service
118-
.with_file_system(Box::new(IsolatedLintHandlerFileSystem::new(
119-
path.to_path_buf(),
120-
Arc::from(source_text),
121-
)))
122-
.with_paths(vec![Arc::from(path.as_os_str())])
123-
.run_source()
123+
.runner
124+
.run_source(&Arc::from(path.as_os_str()), source_text.to_string(), fs)
124125
.iter()
125126
.map(|message| message_to_lsp_diagnostic(message, uri, source_text, rope))
126127
.collect();

crates/oxc_language_server/src/linter/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@ pub mod error_with_position;
33
pub mod isolated_lint_handler;
44
pub mod options;
55
pub mod server_linter;
6-
pub mod tsgo_linter;

crates/oxc_language_server/src/linter/server_linter.rs

Lines changed: 10 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use crate::linter::{
1919
error_with_position::DiagnosticReport,
2020
isolated_lint_handler::{IsolatedLintHandler, IsolatedLintHandlerOptions},
2121
options::{LintOptions as LSPLintOptions, Run},
22-
tsgo_linter::TsgoLinter,
2322
};
2423
use crate::utils::normalize_path;
2524
use crate::{ConcurrentHashMap, LINT_CONFIG_FILE};
@@ -35,7 +34,6 @@ pub enum ServerLinterRun {
3534

3635
pub struct ServerLinter {
3736
isolated_linter: Arc<Mutex<IsolatedLintHandler>>,
38-
tsgo_linter: Arc<Option<TsgoLinter>>,
3937
ignore_matcher: LintIgnoreMatcher,
4038
gitignore_glob: Vec<Gitignore>,
4139
lint_on_run: Run,
@@ -46,7 +44,6 @@ pub struct ServerLinter {
4644
#[derive(Debug, Default)]
4745
struct ServerLinterDiagnostics {
4846
isolated_linter: Arc<ConcurrentHashMap<String, Option<Vec<DiagnosticReport>>>>,
49-
tsgo_linter: Arc<ConcurrentHashMap<String, Option<Vec<DiagnosticReport>>>>,
5047
}
5148

5249
impl ServerLinterDiagnostics {
@@ -59,29 +56,15 @@ impl ServerLinterDiagnostics {
5956
reports.extend(diagnostics.clone());
6057
}
6158
}
62-
if let Some(entry) = self.tsgo_linter.pin().get(path) {
63-
found = true;
64-
if let Some(diagnostics) = entry {
65-
reports.extend(diagnostics.clone());
66-
}
67-
}
6859
if found { Some(reports) } else { None }
6960
}
7061

7162
pub fn remove_diagnostics(&self, path: &str) {
7263
self.isolated_linter.pin().remove(path);
73-
self.tsgo_linter.pin().remove(path);
7464
}
7565

7666
pub fn get_cached_files_of_diagnostics(&self) -> Vec<String> {
77-
let isolated_files = self.isolated_linter.pin().keys().cloned().collect::<Vec<_>>();
78-
let tsgo_files = self.tsgo_linter.pin().keys().cloned().collect::<Vec<_>>();
79-
80-
let mut files = Vec::with_capacity(isolated_files.len() + tsgo_files.len());
81-
files.extend(isolated_files);
82-
files.extend(tsgo_files);
83-
files.dedup();
84-
files
67+
self.isolated_linter.pin().keys().cloned().collect::<Vec<_>>()
8568
}
8669
}
8770

@@ -153,9 +136,10 @@ impl ServerLinter {
153136

154137
let isolated_linter = IsolatedLintHandler::new(
155138
lint_options,
156-
config_store.clone(), // clone because tsgo linter needs it
139+
config_store,
157140
&IsolatedLintHandlerOptions {
158141
use_cross_module,
142+
type_aware: options.type_aware,
159143
root_path: root_path.to_path_buf(),
160144
tsconfig_path: options.ts_config_path.as_ref().map(|path| {
161145
let path = Path::new(path).to_path_buf();
@@ -175,11 +159,6 @@ impl ServerLinter {
175159
extended_paths,
176160
lint_on_run: options.run,
177161
diagnostics: ServerLinterDiagnostics::default(),
178-
tsgo_linter: if options.type_aware {
179-
Arc::new(Some(TsgoLinter::new(&root_path, config_store)))
180-
} else {
181-
Arc::new(None)
182-
},
183162
}
184163
}
185164

@@ -336,10 +315,7 @@ impl ServerLinter {
336315
(ServerLinterRun::OnType, Run::OnSave) => (false, false),
337316
// In onType mode, only TypeScript type checking runs on save
338317
// If type_aware is disabled (tsgo_linter is None), skip everything to preserve diagnostics
339-
(ServerLinterRun::OnSave, Run::OnType) => {
340-
let should_run_tsgo = self.tsgo_linter.as_ref().is_some();
341-
(false, should_run_tsgo)
342-
}
318+
(ServerLinterRun::OnSave, Run::OnType) => (false, true),
343319
};
344320

345321
// return `None` when both tools do not want to be used
@@ -359,13 +335,6 @@ impl ServerLinter {
359335
self.diagnostics.isolated_linter.pin().insert(uri.to_string(), diagnostics);
360336
}
361337

362-
if tsgolint && let Some(tsgo_linter) = self.tsgo_linter.as_ref() {
363-
self.diagnostics
364-
.tsgo_linter
365-
.pin()
366-
.insert(uri.to_string(), tsgo_linter.lint_file(uri, content.clone()));
367-
}
368-
369338
self.diagnostics.get_diagnostics(&uri.to_string())
370339
}
371340

@@ -466,31 +435,23 @@ mod test {
466435
fn test_get_diagnostics_found_and_none_entries() {
467436
let key = "file:///test.js".to_string();
468437

469-
// Case 1: Both entries present, Some diagnostics
438+
// Case 1: Entry present, Some diagnostics
470439
let diag = DiagnosticReport::default();
471440
let diag_map = ConcurrentHashMap::default();
472-
diag_map.pin().insert(key.clone(), Some(vec![diag.clone()]));
473-
let tsgo_map = ConcurrentHashMap::default();
474-
tsgo_map.pin().insert(key.clone(), Some(vec![diag]));
441+
diag_map.pin().insert(key.clone(), Some(vec![diag]));
475442

476-
let server_diag = super::ServerLinterDiagnostics {
477-
isolated_linter: std::sync::Arc::new(diag_map),
478-
tsgo_linter: std::sync::Arc::new(tsgo_map),
479-
};
443+
let server_diag =
444+
super::ServerLinterDiagnostics { isolated_linter: std::sync::Arc::new(diag_map) };
480445
let result = server_diag.get_diagnostics(&key);
481446
assert!(result.is_some());
482447
assert_eq!(result.unwrap().len(), 2);
483448

484449
// Case 2: Entry present, but value is None
485450
let diag_map_none = ConcurrentHashMap::default();
486451
diag_map_none.pin().insert(key.clone(), None);
487-
let tsgo_map_none = ConcurrentHashMap::default();
488-
tsgo_map_none.pin().insert(key.clone(), None);
489452

490-
let server_diag_none = ServerLinterDiagnostics {
491-
isolated_linter: std::sync::Arc::new(diag_map_none),
492-
tsgo_linter: std::sync::Arc::new(tsgo_map_none),
493-
};
453+
let server_diag_none =
454+
ServerLinterDiagnostics { isolated_linter: std::sync::Arc::new(diag_map_none) };
494455
let result_none = server_diag_none.get_diagnostics(&key);
495456
assert!(result_none.is_some());
496457
assert_eq!(result_none.unwrap().len(), 0);

crates/oxc_language_server/src/linter/tsgo_linter.rs

Lines changed: 0 additions & 67 deletions
This file was deleted.

crates/oxc_linter/src/lint_runner.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ use crate::{
1313
AllowWarnDeny, DisableDirectives, LintService, LintServiceOptions, Linter, TsGoLintState,
1414
};
1515

16+
#[cfg(feature = "language_server")]
17+
use crate::Message;
18+
1619
/// Unified runner that orchestrates both regular (oxc) and type-aware (tsgolint) linting
1720
/// with centralized disable directives handling.
1821
pub struct LintRunner {
@@ -217,6 +220,30 @@ impl LintRunner {
217220
Ok(self)
218221
}
219222

223+
/// Run both regular and type-aware linting on files
224+
/// # Errors
225+
/// Returns an error if type-aware linting fails.
226+
#[cfg(feature = "language_server")]
227+
pub fn run_source(
228+
&mut self,
229+
file: &Arc<OsStr>,
230+
source_text: String,
231+
file_system: Box<dyn crate::RuntimeFileSystem + Sync + Send>,
232+
) -> Vec<Message> {
233+
self.lint_service.with_paths(vec![Arc::clone(file)]);
234+
self.lint_service.with_file_system(file_system);
235+
236+
let mut messages = self.lint_service.run_source();
237+
238+
if let Some(type_aware_linter) = self.type_aware_linter.take()
239+
&& let Ok(tso_messages) = type_aware_linter.lint_source(file, source_text)
240+
{
241+
messages.extend(tso_messages);
242+
}
243+
244+
messages
245+
}
246+
220247
/// Report unused disable directives
221248
pub fn report_unused_directives(
222249
&self,

0 commit comments

Comments
 (0)