diff --git a/crates/oxc_language_server/src/linter/isolated_lint_handler.rs b/crates/oxc_language_server/src/linter/isolated_lint_handler.rs index fb0e76ed6931b..a370654dbb30b 100644 --- a/crates/oxc_language_server/src/linter/isolated_lint_handler.rs +++ b/crates/oxc_language_server/src/linter/isolated_lint_handler.rs @@ -10,9 +10,9 @@ use tower_lsp_server::{UriExt, lsp_types::Uri}; use oxc_allocator::Allocator; use oxc_linter::{ - AllowWarnDeny, ConfigStore, DirectivesStore, DisableDirectives, Fix, LINTABLE_EXTENSIONS, - LintOptions, LintService, LintServiceOptions, Linter, Message, PossibleFixes, RuleCommentType, - RuntimeFileSystem, read_to_arena_str, read_to_string, + AllowWarnDeny, ConfigStore, DisableDirectives, Fix, FixKind, LINTABLE_EXTENSIONS, LintOptions, + LintRunner, LintRunnerBuilder, LintServiceOptions, Linter, Message, PossibleFixes, + RuleCommentType, RuntimeFileSystem, read_to_arena_str, read_to_string, }; use super::error_with_position::{ @@ -23,13 +23,14 @@ use super::error_with_position::{ #[derive(Debug, Clone)] pub struct IsolatedLintHandlerOptions { pub use_cross_module: bool, + pub type_aware: bool, + pub fix_kind: FixKind, pub root_path: PathBuf, pub tsconfig_path: Option, } pub struct IsolatedLintHandler { - service: LintService, - directives_coordinator: DirectivesStore, + runner: LintRunner, unused_directives_severity: Option, } @@ -68,8 +69,6 @@ impl IsolatedLintHandler { config_store: ConfigStore, options: &IsolatedLintHandlerOptions, ) -> Self { - let directives_coordinator = DirectivesStore::new(); - let linter = Linter::new(lint_options, config_store, None); let mut lint_service_options = LintServiceOptions::new(options.root_path.clone()) .with_cross_module(options.use_cross_module); @@ -81,12 +80,12 @@ impl IsolatedLintHandler { lint_service_options = lint_service_options.with_tsconfig(tsconfig_path); } - let mut service = LintService::new(linter, lint_service_options); - service.set_disable_directives_map(directives_coordinator.map()); - Self { - service, - directives_coordinator, + runner: LintRunnerBuilder::new(lint_service_options, linter) + .with_type_aware(options.type_aware) + .with_fix_kind(options.fix_kind) + .build() + .unwrap(), unused_directives_severity: lint_options.report_unused_directive, } } @@ -113,21 +112,21 @@ impl IsolatedLintHandler { debug!("lint {}", path.display()); let rope = &Rope::from_str(source_text); + let fs = Box::new(IsolatedLintHandlerFileSystem::new( + path.to_path_buf(), + Arc::from(source_text), + )); + let mut messages: Vec = self - .service - .with_file_system(Box::new(IsolatedLintHandlerFileSystem::new( - path.to_path_buf(), - Arc::from(source_text), - ))) - .with_paths(vec![Arc::from(path.as_os_str())]) - .run_source() + .runner + .run_source(&Arc::from(path.as_os_str()), source_text.to_string(), fs) .iter() .map(|message| message_to_lsp_diagnostic(message, uri, source_text, rope)) .collect(); // Add unused directives if configured if let Some(severity) = self.unused_directives_severity - && let Some(directives) = self.directives_coordinator.get(path) + && let Some(directives) = self.runner.directives_coordinator().get(path) { messages.extend( create_unused_directives_messages(&directives, severity, source_text) diff --git a/crates/oxc_language_server/src/linter/mod.rs b/crates/oxc_language_server/src/linter/mod.rs index 4353f7a2d2b1c..bab683f57a6ce 100644 --- a/crates/oxc_language_server/src/linter/mod.rs +++ b/crates/oxc_language_server/src/linter/mod.rs @@ -3,4 +3,3 @@ pub mod error_with_position; pub mod isolated_lint_handler; pub mod options; pub mod server_linter; -pub mod tsgo_linter; diff --git a/crates/oxc_language_server/src/linter/server_linter.rs b/crates/oxc_language_server/src/linter/server_linter.rs index b636ffc798fd5..ed2aa9fee716f 100644 --- a/crates/oxc_language_server/src/linter/server_linter.rs +++ b/crates/oxc_language_server/src/linter/server_linter.rs @@ -19,7 +19,6 @@ use crate::linter::{ error_with_position::DiagnosticReport, isolated_lint_handler::{IsolatedLintHandler, IsolatedLintHandlerOptions}, options::{LintOptions as LSPLintOptions, Run}, - tsgo_linter::TsgoLinter, }; use crate::utils::normalize_path; use crate::{ConcurrentHashMap, LINT_CONFIG_FILE}; @@ -33,9 +32,19 @@ pub enum ServerLinterRun { Always, } +impl ServerLinterRun { + fn matches(&self, run: Run) -> bool { + matches!( + (self, run), + (ServerLinterRun::OnType, Run::OnType) + | (ServerLinterRun::OnSave, Run::OnSave) + | (ServerLinterRun::Always, _) + ) + } +} + pub struct ServerLinter { isolated_linter: Arc>, - tsgo_linter: Arc>, ignore_matcher: LintIgnoreMatcher, gitignore_glob: Vec, lint_on_run: Run, @@ -46,7 +55,6 @@ pub struct ServerLinter { #[derive(Debug, Default)] struct ServerLinterDiagnostics { isolated_linter: Arc>>>, - tsgo_linter: Arc>>>, } impl ServerLinterDiagnostics { @@ -59,29 +67,15 @@ impl ServerLinterDiagnostics { reports.extend(diagnostics.clone()); } } - if let Some(entry) = self.tsgo_linter.pin().get(path) { - found = true; - if let Some(diagnostics) = entry { - reports.extend(diagnostics.clone()); - } - } if found { Some(reports) } else { None } } pub fn remove_diagnostics(&self, path: &str) { self.isolated_linter.pin().remove(path); - self.tsgo_linter.pin().remove(path); } pub fn get_cached_files_of_diagnostics(&self) -> Vec { - let isolated_files = self.isolated_linter.pin().keys().cloned().collect::>(); - let tsgo_files = self.tsgo_linter.pin().keys().cloned().collect::>(); - - let mut files = Vec::with_capacity(isolated_files.len() + tsgo_files.len()); - files.extend(isolated_files); - files.extend(tsgo_files); - files.dedup(); - files + self.isolated_linter.pin().keys().cloned().collect::>() } } @@ -156,9 +150,11 @@ impl ServerLinter { let isolated_linter = IsolatedLintHandler::new( lint_options, - config_store.clone(), // clone because tsgo linter needs it + config_store, &IsolatedLintHandlerOptions { use_cross_module, + type_aware: options.type_aware, + fix_kind: FixKind::from(options.fix_kind.clone()), root_path: root_path.to_path_buf(), tsconfig_path: options.ts_config_path.as_ref().map(|path| { let path = Path::new(path).to_path_buf(); @@ -178,11 +174,6 @@ impl ServerLinter { extended_paths, lint_on_run: options.run, diagnostics: ServerLinterDiagnostics::default(), - tsgo_linter: if options.type_aware { - Arc::new(Some(TsgoLinter::new(&root_path, config_store, fix_kind))) - } else { - Arc::new(None) - }, } } @@ -329,24 +320,10 @@ impl ServerLinter { content: Option, run_type: ServerLinterRun, ) -> Option> { - let (oxlint, tsgolint) = match (run_type, self.lint_on_run) { - // run everything on save, or when it is forced - (ServerLinterRun::Always, _) | (ServerLinterRun::OnSave, Run::OnSave) => (true, true), - // run only oxlint on type - // tsgolint does not support memory source_text - (ServerLinterRun::OnType, Run::OnType) => (true, false), - // it does not match, run nothing - (ServerLinterRun::OnType, Run::OnSave) => (false, false), - // In onType mode, only TypeScript type checking runs on save - // If type_aware is disabled (tsgo_linter is None), skip everything to preserve diagnostics - (ServerLinterRun::OnSave, Run::OnType) => { - let should_run_tsgo = self.tsgo_linter.as_ref().is_some(); - (false, should_run_tsgo) - } - }; + let run = matches!(run_type, ServerLinterRun::Always) || run_type.matches(self.lint_on_run); // return `None` when both tools do not want to be used - if !oxlint && !tsgolint { + if !run { return None; } @@ -354,22 +331,14 @@ impl ServerLinter { return None; } - if oxlint { - let diagnostics = { - let mut isolated_linter = self.isolated_linter.lock().await; - isolated_linter.run_single(uri, content.clone()) - }; - self.diagnostics.isolated_linter.pin().insert(uri.to_string(), diagnostics); - } + let diagnostics = { + let mut isolated_linter = self.isolated_linter.lock().await; + isolated_linter.run_single(uri, content.clone()) + }; - if tsgolint && let Some(tsgo_linter) = self.tsgo_linter.as_ref() { - self.diagnostics - .tsgo_linter - .pin() - .insert(uri.to_string(), tsgo_linter.lint_file(uri, content.clone())); - } + self.diagnostics.isolated_linter.pin().insert(uri.to_string(), diagnostics.clone()); - self.diagnostics.get_diagnostics(&uri.to_string()) + diagnostics } pub fn needs_restart(old_options: &LSPLintOptions, new_options: &LSPLintOptions) -> bool { @@ -465,31 +434,23 @@ mod test { fn test_get_diagnostics_found_and_none_entries() { let key = "file:///test.js".to_string(); - // Case 1: Both entries present, Some diagnostics + // Case 1: Entry present, Some diagnostics let diag = DiagnosticReport::default(); let diag_map = ConcurrentHashMap::default(); - diag_map.pin().insert(key.clone(), Some(vec![diag.clone()])); - let tsgo_map = ConcurrentHashMap::default(); - tsgo_map.pin().insert(key.clone(), Some(vec![diag])); + diag_map.pin().insert(key.clone(), Some(vec![diag])); - let server_diag = super::ServerLinterDiagnostics { - isolated_linter: std::sync::Arc::new(diag_map), - tsgo_linter: std::sync::Arc::new(tsgo_map), - }; + let server_diag = + super::ServerLinterDiagnostics { isolated_linter: std::sync::Arc::new(diag_map) }; let result = server_diag.get_diagnostics(&key); assert!(result.is_some()); - assert_eq!(result.unwrap().len(), 2); + assert_eq!(result.unwrap().len(), 1); // Case 2: Entry present, but value is None let diag_map_none = ConcurrentHashMap::default(); diag_map_none.pin().insert(key.clone(), None); - let tsgo_map_none = ConcurrentHashMap::default(); - tsgo_map_none.pin().insert(key.clone(), None); - let server_diag_none = ServerLinterDiagnostics { - isolated_linter: std::sync::Arc::new(diag_map_none), - tsgo_linter: std::sync::Arc::new(tsgo_map_none), - }; + let server_diag_none = + ServerLinterDiagnostics { isolated_linter: std::sync::Arc::new(diag_map_none) }; let result_none = server_diag_none.get_diagnostics(&key); assert!(result_none.is_some()); assert_eq!(result_none.unwrap().len(), 0); @@ -505,14 +466,19 @@ mod test { fn test_lint_on_run_on_type_on_type() { Tester::new( "fixtures/linter/lint_on_run/on_type", - Some(LintOptions { type_aware: true, run: Run::OnType, ..Default::default() }), + Some(LintOptions { + type_aware: true, + run: Run::OnType, + fix_kind: LintFixKindFlag::All, + ..Default::default() + }), ) .test_and_snapshot_single_file_with_run_type("on-type.ts", Run::OnType); } #[test] #[cfg(not(target_endian = "big"))] - fn test_lint_on_run_on_type_on_save() { + fn test_lint_on_run_on_save_on_save() { Tester::new( "fixtures/linter/lint_on_run/on_save", Some(LintOptions { @@ -537,12 +503,12 @@ mod test { #[test] #[cfg(not(target_endian = "big"))] - fn test_lint_on_run_on_save_on_save() { + fn test_lint_on_run_on_type_on_save() { Tester::new( - "fixtures/linter/lint_on_run/on_type", + "fixtures/linter/lint_on_run/on_save", Some(LintOptions { type_aware: true, - run: Run::OnSave, + run: Run::OnType, fix_kind: LintFixKindFlag::All, ..Default::default() }), @@ -676,7 +642,6 @@ mod test { "fixtures/linter/tsgolint", Some(LintOptions { type_aware: true, - run: Run::OnSave, fix_kind: LintFixKindFlag::All, ..Default::default() }), @@ -686,10 +651,7 @@ mod test { #[test] fn test_ignore_js_plugins() { - let tester = Tester::new( - "fixtures/linter/js_plugins", - Some(LintOptions { run: Run::OnSave, ..Default::default() }), - ); + let tester = Tester::new("fixtures/linter/js_plugins", Some(LintOptions::default())); tester.test_and_snapshot_single_file("index.js"); } diff --git a/crates/oxc_language_server/src/linter/tsgo_linter.rs b/crates/oxc_language_server/src/linter/tsgo_linter.rs deleted file mode 100644 index e484cff22800a..0000000000000 --- a/crates/oxc_language_server/src/linter/tsgo_linter.rs +++ /dev/null @@ -1,74 +0,0 @@ -use std::{ - path::Path, - sync::{Arc, OnceLock}, -}; - -use log::error; -use oxc_data_structures::rope::Rope; -use oxc_linter::{ - ConfigStore, FixKind, LINTABLE_EXTENSIONS, TsGoLintState, - loader::LINT_PARTIAL_LOADER_EXTENSIONS, read_to_string, -}; -use rustc_hash::FxHashSet; -use tower_lsp_server::{UriExt, lsp_types::Uri}; - -use crate::linter::error_with_position::{ - DiagnosticReport, generate_inverted_diagnostics, message_to_lsp_diagnostic, -}; - -pub struct TsgoLinter { - state: TsGoLintState, -} - -impl TsgoLinter { - pub fn new(root_uri: &Path, config_store: ConfigStore, fix_kind: FixKind) -> Self { - let state = TsGoLintState::new(root_uri, config_store, fix_kind); - Self { state } - } - - pub fn lint_file(&self, uri: &Uri, content: Option) -> Option> { - let path = uri.to_file_path()?; - - if !Self::should_lint_path(&path) { - return None; - } - - let source_text = content.or_else(|| read_to_string(&path).ok())?; - let rope = Rope::from_str(&source_text); - - // TODO: Avoid cloning the source text - let messages = - match self.state.lint_source(&Arc::from(path.as_os_str()), source_text.clone()) { - Ok(messages) => messages, - Err(err) => { - error!("tsgolint failed to lint file {}: {err}", uri.path()); - return None; - } - }; - - let mut diagnostics: Vec = messages - .iter() - .map(|e| message_to_lsp_diagnostic(e, uri, &source_text, &rope)) - .collect(); - - let mut inverted_diagnostics = generate_inverted_diagnostics(&diagnostics, uri); - diagnostics.append(&mut inverted_diagnostics); - - Some(diagnostics) - } - - fn should_lint_path(path: &Path) -> bool { - static WANTED_EXTENSIONS: OnceLock> = OnceLock::new(); - let wanted_exts = WANTED_EXTENSIONS.get_or_init(|| { - LINTABLE_EXTENSIONS - .iter() - .filter(|ext| !LINT_PARTIAL_LOADER_EXTENSIONS.contains(ext)) - .copied() - .collect() - }); - - path.extension() - .and_then(std::ffi::OsStr::to_str) - .is_some_and(|ext| wanted_exts.contains(ext)) - } -} diff --git a/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_save@on-save.ts.snap b/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_save@on-save.ts.snap index 99694c68a7051..bdd699e1fd9ea 100644 --- a/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_save@on-save.ts.snap +++ b/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_save@on-save.ts.snap @@ -4,82 +4,4 @@ source: crates/oxc_language_server/src/tester.rs ########## file: fixtures/linter/lint_on_run/on_save/on-save.ts ---------- - -code: "typescript-eslint(no-floating-promises)" -code_description.href: "None" -message: "Promises must be awaited.\nhelp: The promise must end with a call to .catch, or end with a call to .then with a rejection handler, or be explicitly marked as ignored with the `void` operator." -range: Range { start: Position { line: 7, character: 0 }, end: Position { line: 7, character: 32 } } -related_information[0].message: "" -related_information[0].location.uri: "file:///fixtures/linter/lint_on_run/on_save/on-save.ts" -related_information[0].location.range: Range { start: Position { line: 7, character: 0 }, end: Position { line: 7, character: 32 } } -severity: Some(Warning) -source: Some("oxc") -tags: None -fixed: Multiple( - [ - FixedContent { - message: Some( - "Promises must be awaited.", - ), - code: "void ", - range: Range { - start: Position { - line: 7, - character: 0, - }, - end: Position { - line: 7, - character: 0, - }, - }, - }, - FixedContent { - message: Some( - "Promises must be awaited.", - ), - code: "await ", - range: Range { - start: Position { - line: 7, - character: 0, - }, - end: Position { - line: 7, - character: 0, - }, - }, - }, - FixedContent { - message: Some( - "Disable no-floating-promises for this line", - ), - code: "// oxlint-disable-next-line no-floating-promises\n", - range: Range { - start: Position { - line: 7, - character: 0, - }, - end: Position { - line: 7, - character: 0, - }, - }, - }, - FixedContent { - message: Some( - "Disable no-floating-promises for this file", - ), - code: "// oxlint-disable no-floating-promises\n", - range: Range { - start: Position { - line: 0, - character: 0, - }, - end: Position { - line: 0, - character: 0, - }, - }, - }, - ], -) +File is ignored diff --git a/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_type@on-save.ts.snap b/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_type@on-save.ts.snap deleted file mode 100644 index aa164ae89a6be..0000000000000 --- a/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_type@on-save.ts.snap +++ /dev/null @@ -1,149 +0,0 @@ ---- -source: crates/oxc_language_server/src/tester.rs ---- -########## -file: fixtures/linter/lint_on_run/on_type/on-save.ts ----------- - -code: "eslint(no-debugger)" -code_description.href: "https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-debugger.html" -message: "`debugger` statement is not allowed\nhelp: Remove the debugger statement" -range: Range { start: Position { line: 1, character: 0 }, end: Position { line: 1, character: 9 } } -related_information[0].message: "" -related_information[0].location.uri: "file:///fixtures/linter/lint_on_run/on_type/on-save.ts" -related_information[0].location.range: Range { start: Position { line: 1, character: 0 }, end: Position { line: 1, character: 9 } } -severity: Some(Warning) -source: Some("oxc") -tags: None -fixed: Multiple( - [ - FixedContent { - message: Some( - "Remove the debugger statement", - ), - code: "", - range: Range { - start: Position { - line: 1, - character: 0, - }, - end: Position { - line: 1, - character: 9, - }, - }, - }, - FixedContent { - message: Some( - "Disable no-debugger for this line", - ), - code: "// oxlint-disable-next-line no-debugger\n", - range: Range { - start: Position { - line: 1, - character: 0, - }, - end: Position { - line: 1, - character: 0, - }, - }, - }, - FixedContent { - message: Some( - "Disable no-debugger for this file", - ), - code: "// oxlint-disable no-debugger\n", - range: Range { - start: Position { - line: 0, - character: 0, - }, - end: Position { - line: 0, - character: 0, - }, - }, - }, - ], -) - - -code: "typescript-eslint(no-floating-promises)" -code_description.href: "None" -message: "Promises must be awaited.\nhelp: The promise must end with a call to .catch, or end with a call to .then with a rejection handler, or be explicitly marked as ignored with the `void` operator." -range: Range { start: Position { line: 7, character: 0 }, end: Position { line: 7, character: 32 } } -related_information[0].message: "" -related_information[0].location.uri: "file:///fixtures/linter/lint_on_run/on_type/on-save.ts" -related_information[0].location.range: Range { start: Position { line: 7, character: 0 }, end: Position { line: 7, character: 32 } } -severity: Some(Warning) -source: Some("oxc") -tags: None -fixed: Multiple( - [ - FixedContent { - message: Some( - "Promises must be awaited.", - ), - code: "void ", - range: Range { - start: Position { - line: 7, - character: 0, - }, - end: Position { - line: 7, - character: 0, - }, - }, - }, - FixedContent { - message: Some( - "Promises must be awaited.", - ), - code: "await ", - range: Range { - start: Position { - line: 7, - character: 0, - }, - end: Position { - line: 7, - character: 0, - }, - }, - }, - FixedContent { - message: Some( - "Disable no-floating-promises for this line", - ), - code: "// oxlint-disable-next-line no-floating-promises\n", - range: Range { - start: Position { - line: 7, - character: 0, - }, - end: Position { - line: 7, - character: 0, - }, - }, - }, - FixedContent { - message: Some( - "Disable no-floating-promises for this file", - ), - code: "// oxlint-disable no-floating-promises\n", - range: Range { - start: Position { - line: 0, - character: 0, - }, - end: Position { - line: 0, - character: 0, - }, - }, - }, - ], -) diff --git a/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_type@on-type.ts.snap b/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_type@on-type.ts.snap index 44c02019338f2..cb6630f8df32b 100644 --- a/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_type@on-type.ts.snap +++ b/crates/oxc_language_server/src/snapshots/fixtures_linter_lint_on_run_on_type@on-type.ts.snap @@ -67,3 +67,83 @@ fixed: Multiple( }, ], ) + + +code: "typescript-eslint(no-floating-promises)" +code_description.href: "None" +message: "Promises must be awaited.\nhelp: The promise must end with a call to .catch, or end with a call to .then with a rejection handler, or be explicitly marked as ignored with the `void` operator." +range: Range { start: Position { line: 7, character: 0 }, end: Position { line: 7, character: 32 } } +related_information[0].message: "" +related_information[0].location.uri: "file:///fixtures/linter/lint_on_run/on_type/on-type.ts" +related_information[0].location.range: Range { start: Position { line: 7, character: 0 }, end: Position { line: 7, character: 32 } } +severity: Some(Warning) +source: Some("oxc") +tags: None +fixed: Multiple( + [ + FixedContent { + message: Some( + "Promises must be awaited.", + ), + code: "void ", + range: Range { + start: Position { + line: 7, + character: 0, + }, + end: Position { + line: 7, + character: 0, + }, + }, + }, + FixedContent { + message: Some( + "Promises must be awaited.", + ), + code: "await ", + range: Range { + start: Position { + line: 7, + character: 0, + }, + end: Position { + line: 7, + character: 0, + }, + }, + }, + FixedContent { + message: Some( + "Disable no-floating-promises for this line", + ), + code: "// oxlint-disable-next-line no-floating-promises\n", + range: Range { + start: Position { + line: 7, + character: 0, + }, + end: Position { + line: 7, + character: 0, + }, + }, + }, + FixedContent { + message: Some( + "Disable no-floating-promises for this file", + ), + code: "// oxlint-disable no-floating-promises\n", + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + }, + ], +) diff --git a/crates/oxc_linter/src/lint_runner.rs b/crates/oxc_linter/src/lint_runner.rs index 3113982c0c1dd..78d6af066fe18 100644 --- a/crates/oxc_linter/src/lint_runner.rs +++ b/crates/oxc_linter/src/lint_runner.rs @@ -14,6 +14,9 @@ use crate::{ TsGoLintState, }; +#[cfg(feature = "language_server")] +use crate::Message; + /// Unified runner that orchestrates both regular (oxc) and type-aware (tsgolint) linting /// with centralized disable directives handling. pub struct LintRunner { @@ -225,6 +228,30 @@ impl LintRunner { Ok(self) } + /// Run both regular and type-aware linting on files + /// # Errors + /// Returns an error if type-aware linting fails. + #[cfg(feature = "language_server")] + pub fn run_source( + &mut self, + file: &Arc, + source_text: String, + file_system: Box, + ) -> Vec { + self.lint_service.with_paths(vec![Arc::clone(file)]); + self.lint_service.with_file_system(file_system); + + let mut messages = self.lint_service.run_source(); + + if let Some(type_aware_linter) = &self.type_aware_linter + && let Ok(tso_messages) = type_aware_linter.lint_source(file, source_text) + { + messages.extend(tso_messages); + } + + messages + } + /// Report unused disable directives pub fn report_unused_directives( &self, diff --git a/editors/vscode/tests/e2e_server.spec.ts b/editors/vscode/tests/e2e_server.spec.ts index 8cdccb0a3d6b1..a4859a9644e41 100644 --- a/editors/vscode/tests/e2e_server.spec.ts +++ b/editors/vscode/tests/e2e_server.spec.ts @@ -92,8 +92,8 @@ suite('E2E Diagnostics', () => { test('empty oxlint configuration behaves like default configuration', async () => { await loadFixture('debugger_empty_config'); - await sleep(250); - const diagnostics = await getDiagnostics('debugger.js'); + await sleep(500); + const diagnostics = await getDiagnosticsWithoutClose('debugger.js'); strictEqual(diagnostics.length, 1); assert(typeof diagnostics[0].code == 'object'); @@ -264,10 +264,10 @@ suite('E2E Diagnostics', () => { // flaky because of https://github.com/oxc-project/tsgolint/issues/349 test.skip('changing oxc.typeAware will revalidate the tsgolint diagnostics', async () => { await loadFixture('type_aware'); - const firstDiagnostics = await getDiagnostics('index.ts'); + await sleep(500); // wait for server to pick up the new config + const firstDiagnostics = await getDiagnosticsWithoutClose('index.ts'); await workspace.getConfiguration('oxc').update('fixKind', 'all'); - strictEqual(firstDiagnostics.length, 0); await workspace.getConfiguration('oxc').update('typeAware', true);