Skip to content

Commit 716cfc9

Browse files
committed
refactor(language_server): use LintRunner
1 parent 0e01d98 commit 716cfc9

File tree

9 files changed

+162
-393
lines changed

9 files changed

+162
-393
lines changed

crates/oxc_language_server/src/linter/isolated_lint_handler.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use tower_lsp_server::{UriExt, lsp_types::Uri};
1010

1111
use oxc_allocator::Allocator;
1212
use oxc_linter::{
13-
AllowWarnDeny, ConfigStore, DirectivesStore, DisableDirectives, Fix, LINTABLE_EXTENSIONS,
14-
LintOptions, LintService, LintServiceOptions, Linter, Message, PossibleFixes, RuleCommentType,
15-
RuntimeFileSystem, read_to_arena_str, read_to_string,
13+
AllowWarnDeny, ConfigStore, DisableDirectives, Fix, LINTABLE_EXTENSIONS, LintOptions,
14+
LintRunner, LintRunnerBuilder, LintServiceOptions, Linter, Message, PossibleFixes,
15+
RuleCommentType, RuntimeFileSystem, read_to_arena_str, read_to_string,
1616
};
1717

1818
use super::error_with_position::{
@@ -23,13 +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-
directives_coordinator: DirectivesStore,
32+
runner: LintRunner,
3333
unused_directives_severity: Option<AllowWarnDeny>,
3434
}
3535

@@ -68,8 +68,6 @@ impl IsolatedLintHandler {
6868
config_store: ConfigStore,
6969
options: &IsolatedLintHandlerOptions,
7070
) -> Self {
71-
let directives_coordinator = DirectivesStore::new();
72-
7371
let linter = Linter::new(lint_options, config_store, None);
7472
let mut lint_service_options = LintServiceOptions::new(options.root_path.clone())
7573
.with_cross_module(options.use_cross_module);
@@ -81,12 +79,11 @@ impl IsolatedLintHandler {
8179
lint_service_options = lint_service_options.with_tsconfig(tsconfig_path);
8280
}
8381

84-
let mut service = LintService::new(linter, lint_service_options);
85-
service.set_disable_directives_map(directives_coordinator.map());
86-
8782
Self {
88-
service,
89-
directives_coordinator,
83+
runner: LintRunnerBuilder::new(lint_service_options, linter)
84+
.with_type_aware(options.type_aware)
85+
.build()
86+
.unwrap(),
9087
unused_directives_severity: lint_options.report_unused_directive,
9188
}
9289
}
@@ -113,21 +110,21 @@ impl IsolatedLintHandler {
113110
debug!("lint {}", path.display());
114111
let rope = &Rope::from_str(source_text);
115112

113+
let fs = Box::new(IsolatedLintHandlerFileSystem::new(
114+
path.to_path_buf(),
115+
Arc::from(source_text),
116+
));
117+
116118
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()
119+
.runner
120+
.run_source(&Arc::from(path.as_os_str()), source_text.to_string(), fs)
124121
.iter()
125122
.map(|message| message_to_lsp_diagnostic(message, uri, source_text, rope))
126123
.collect();
127124

128125
// Add unused directives if configured
129126
if let Some(severity) = self.unused_directives_severity
130-
&& let Some(directives) = self.directives_coordinator.get(path)
127+
&& let Some(directives) = self.runner.directives_coordinator().get(path)
131128
{
132129
messages.extend(
133130
create_unused_directives_messages(&directives, severity, source_text)

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: 33 additions & 73 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};
@@ -33,9 +32,19 @@ pub enum ServerLinterRun {
3332
Always,
3433
}
3534

35+
impl ServerLinterRun {
36+
fn matches(&self, run: Run) -> bool {
37+
matches!(
38+
(self, run),
39+
(ServerLinterRun::OnType, Run::OnType)
40+
| (ServerLinterRun::OnSave, Run::OnSave)
41+
| (ServerLinterRun::Always, _)
42+
)
43+
}
44+
}
45+
3646
pub struct ServerLinter {
3747
isolated_linter: Arc<Mutex<IsolatedLintHandler>>,
38-
tsgo_linter: Arc<Option<TsgoLinter>>,
3948
ignore_matcher: LintIgnoreMatcher,
4049
gitignore_glob: Vec<Gitignore>,
4150
lint_on_run: Run,
@@ -46,7 +55,6 @@ pub struct ServerLinter {
4655
#[derive(Debug, Default)]
4756
struct ServerLinterDiagnostics {
4857
isolated_linter: Arc<ConcurrentHashMap<String, Option<Vec<DiagnosticReport>>>>,
49-
tsgo_linter: Arc<ConcurrentHashMap<String, Option<Vec<DiagnosticReport>>>>,
5058
}
5159

5260
impl ServerLinterDiagnostics {
@@ -59,29 +67,15 @@ impl ServerLinterDiagnostics {
5967
reports.extend(diagnostics.clone());
6068
}
6169
}
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-
}
6870
if found { Some(reports) } else { None }
6971
}
7072

7173
pub fn remove_diagnostics(&self, path: &str) {
7274
self.isolated_linter.pin().remove(path);
73-
self.tsgo_linter.pin().remove(path);
7475
}
7576

7677
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
78+
self.isolated_linter.pin().keys().cloned().collect::<Vec<_>>()
8579
}
8680
}
8781

@@ -156,9 +150,10 @@ impl ServerLinter {
156150

157151
let isolated_linter = IsolatedLintHandler::new(
158152
lint_options,
159-
config_store.clone(), // clone because tsgo linter needs it
153+
config_store,
160154
&IsolatedLintHandlerOptions {
161155
use_cross_module,
156+
type_aware: options.type_aware,
162157
root_path: root_path.to_path_buf(),
163158
tsconfig_path: options.ts_config_path.as_ref().map(|path| {
164159
let path = Path::new(path).to_path_buf();
@@ -178,11 +173,6 @@ impl ServerLinter {
178173
extended_paths,
179174
lint_on_run: options.run,
180175
diagnostics: ServerLinterDiagnostics::default(),
181-
tsgo_linter: if options.type_aware {
182-
Arc::new(Some(TsgoLinter::new(&root_path, config_store, fix_kind)))
183-
} else {
184-
Arc::new(None)
185-
},
186176
}
187177
}
188178

@@ -329,47 +319,25 @@ impl ServerLinter {
329319
content: Option<String>,
330320
run_type: ServerLinterRun,
331321
) -> Option<Vec<DiagnosticReport>> {
332-
let (oxlint, tsgolint) = match (run_type, self.lint_on_run) {
333-
// run everything on save, or when it is forced
334-
(ServerLinterRun::Always, _) | (ServerLinterRun::OnSave, Run::OnSave) => (true, true),
335-
// run only oxlint on type
336-
// tsgolint does not support memory source_text
337-
(ServerLinterRun::OnType, Run::OnType) => (true, false),
338-
// it does not match, run nothing
339-
(ServerLinterRun::OnType, Run::OnSave) => (false, false),
340-
// In onType mode, only TypeScript type checking runs on save
341-
// If type_aware is disabled (tsgo_linter is None), skip everything to preserve diagnostics
342-
(ServerLinterRun::OnSave, Run::OnType) => {
343-
let should_run_tsgo = self.tsgo_linter.as_ref().is_some();
344-
(false, should_run_tsgo)
345-
}
346-
};
322+
let run = matches!(run_type, ServerLinterRun::Always) || run_type.matches(self.lint_on_run);
347323

348324
// return `None` when both tools do not want to be used
349-
if !oxlint && !tsgolint {
325+
if !run {
350326
return None;
351327
}
352328

353329
if self.is_ignored(uri) {
354330
return None;
355331
}
356332

357-
if oxlint {
358-
let diagnostics = {
359-
let mut isolated_linter = self.isolated_linter.lock().await;
360-
isolated_linter.run_single(uri, content.clone())
361-
};
362-
self.diagnostics.isolated_linter.pin().insert(uri.to_string(), diagnostics);
363-
}
333+
let diagnostics = {
334+
let mut isolated_linter = self.isolated_linter.lock().await;
335+
isolated_linter.run_single(uri, content.clone())
336+
};
364337

365-
if tsgolint && let Some(tsgo_linter) = self.tsgo_linter.as_ref() {
366-
self.diagnostics
367-
.tsgo_linter
368-
.pin()
369-
.insert(uri.to_string(), tsgo_linter.lint_file(uri, content.clone()));
370-
}
338+
self.diagnostics.isolated_linter.pin().insert(uri.to_string(), diagnostics.clone());
371339

372-
self.diagnostics.get_diagnostics(&uri.to_string())
340+
diagnostics
373341
}
374342

375343
pub fn needs_restart(old_options: &LSPLintOptions, new_options: &LSPLintOptions) -> bool {
@@ -465,31 +433,23 @@ mod test {
465433
fn test_get_diagnostics_found_and_none_entries() {
466434
let key = "file:///test.js".to_string();
467435

468-
// Case 1: Both entries present, Some diagnostics
436+
// Case 1: Entry present, Some diagnostics
469437
let diag = DiagnosticReport::default();
470438
let diag_map = ConcurrentHashMap::default();
471-
diag_map.pin().insert(key.clone(), Some(vec![diag.clone()]));
472-
let tsgo_map = ConcurrentHashMap::default();
473-
tsgo_map.pin().insert(key.clone(), Some(vec![diag]));
439+
diag_map.pin().insert(key.clone(), Some(vec![diag]));
474440

475-
let server_diag = super::ServerLinterDiagnostics {
476-
isolated_linter: std::sync::Arc::new(diag_map),
477-
tsgo_linter: std::sync::Arc::new(tsgo_map),
478-
};
441+
let server_diag =
442+
super::ServerLinterDiagnostics { isolated_linter: std::sync::Arc::new(diag_map) };
479443
let result = server_diag.get_diagnostics(&key);
480444
assert!(result.is_some());
481-
assert_eq!(result.unwrap().len(), 2);
445+
assert_eq!(result.unwrap().len(), 1);
482446

483447
// Case 2: Entry present, but value is None
484448
let diag_map_none = ConcurrentHashMap::default();
485449
diag_map_none.pin().insert(key.clone(), None);
486-
let tsgo_map_none = ConcurrentHashMap::default();
487-
tsgo_map_none.pin().insert(key.clone(), None);
488450

489-
let server_diag_none = ServerLinterDiagnostics {
490-
isolated_linter: std::sync::Arc::new(diag_map_none),
491-
tsgo_linter: std::sync::Arc::new(tsgo_map_none),
492-
};
451+
let server_diag_none =
452+
ServerLinterDiagnostics { isolated_linter: std::sync::Arc::new(diag_map_none) };
493453
let result_none = server_diag_none.get_diagnostics(&key);
494454
assert!(result_none.is_some());
495455
assert_eq!(result_none.unwrap().len(), 0);
@@ -512,7 +472,7 @@ mod test {
512472

513473
#[test]
514474
#[cfg(not(target_endian = "big"))]
515-
fn test_lint_on_run_on_type_on_save() {
475+
fn test_lint_on_run_on_save_on_save() {
516476
Tester::new(
517477
"fixtures/linter/lint_on_run/on_save",
518478
Some(LintOptions {
@@ -537,12 +497,12 @@ mod test {
537497

538498
#[test]
539499
#[cfg(not(target_endian = "big"))]
540-
fn test_lint_on_run_on_save_on_save() {
500+
fn test_lint_on_run_on_type_on_save() {
541501
Tester::new(
542-
"fixtures/linter/lint_on_run/on_type",
502+
"fixtures/linter/lint_on_run/on_save",
543503
Some(LintOptions {
544504
type_aware: true,
545-
run: Run::OnSave,
505+
run: Run::OnType,
546506
fix_kind: LintFixKindFlag::All,
547507
..Default::default()
548508
}),

crates/oxc_language_server/src/linter/tsgo_linter.rs

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

0 commit comments

Comments
 (0)