Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions crates/oxc_language_server/src/linter/server_linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,29 @@ pub struct ServerLinter {
ignore_matcher: LintIgnoreMatcher,
gitignore_glob: Vec<Gitignore>,
lint_on_run: Run,
diagnostics: Arc<ServerLinterDiagnostics>,
pub extended_paths: Vec<PathBuf>,
}

#[derive(Debug, Default)]
struct ServerLinterDiagnostics {
isolated_linter: Arc<ConcurrentHashMap<String, Vec<DiagnosticReport>>>,
tsgo_linter: Arc<ConcurrentHashMap<String, Vec<DiagnosticReport>>>,
}

impl ServerLinterDiagnostics {
pub fn all_diagnostics(&self, path: &str) -> Vec<DiagnosticReport> {
let mut diagnostics = Vec::new();
if let Some(reports) = self.isolated_linter.pin().get(path) {
diagnostics.extend_from_slice(reports);
}
if let Some(reports) = self.tsgo_linter.pin().get(path) {
diagnostics.extend_from_slice(reports);
}
diagnostics
}
}

impl ServerLinter {
pub fn new(root_uri: &Uri, options: &Options) -> Self {
let root_path = root_uri.to_file_path().unwrap();
Expand Down Expand Up @@ -134,6 +154,7 @@ impl ServerLinter {
gitignore_glob: Self::create_ignore_glob(&root_path),
extended_paths,
lint_on_run: options.run,
diagnostics: Arc::new(ServerLinterDiagnostics::default()),
tsgo_linter: if options.type_aware {
Arc::new(Some(TsgoLinter::new(&root_path, config_store)))
} else {
Expand Down Expand Up @@ -276,28 +297,26 @@ impl ServerLinter {
return None;
}

let mut reports = Vec::with_capacity(0);

if oxlint
&& let Some(oxlint_reports) =
self.isolated_linter.lock().await.run_single(uri, content.clone())
{
reports.extend(oxlint_reports);
self.diagnostics.isolated_linter.pin().insert(uri.to_string(), oxlint_reports);
}

if !tsgolint {
return Some(reports);
return Some(self.diagnostics.all_diagnostics(&uri.to_string()));
}

let Some(tsgo_linter) = &*self.tsgo_linter else {
return Some(reports);
return Some(self.diagnostics.all_diagnostics(&uri.to_string()));
};

if let Some(tsgo_reports) = tsgo_linter.lint_file(uri, content) {
reports.extend(tsgo_reports);
self.diagnostics.tsgo_linter.pin().insert(uri.to_string(), tsgo_reports);
}

Some(reports)
Some(self.diagnostics.all_diagnostics(&uri.to_string()))
}
}

Expand Down
5 changes: 5 additions & 0 deletions editors/vscode/fixtures/lint_on_run/.oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"unicorn/no-empty-file": "off"
}
}
Empty file.
22 changes: 21 additions & 1 deletion editors/vscode/tests/e2e_server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import {
createOxlintConfiguration,
fixturesWorkspaceUri,
getDiagnostics,
getDiagnosticsWithoutClose,
loadFixture,
sleep,
testSingleFolderMode,
waitForDiagnosticChange,
WORKSPACE_DIR
WORKSPACE_DIR,
writeToFixtureFile
} from './test-helpers';
import assert = require('assert');

Expand Down Expand Up @@ -66,6 +68,24 @@ suite('E2E Diagnostics', () => {
});
}

testSingleFolderMode('detects diagnostics on run', async () =>
{
await loadFixture('lint_on_run');
const diagnostics = await getDiagnosticsWithoutClose(`onType.ts`);
strictEqual(diagnostics.length, 0);

await writeToFixtureFile('onType.ts', 'debugger;');
await waitForDiagnosticChange();
const updatedDiagnostics = await getDiagnosticsWithoutClose(`onType.ts`);
strictEqual(updatedDiagnostics.length, 1);

await workspace.saveAll();
await sleep(500);

const sameDiagnostics = await getDiagnosticsWithoutClose(`onType.ts`);
strictEqual(updatedDiagnostics.length, sameDiagnostics.length);
});

test('empty oxlint configuration behaves like default configuration', async () => {
await loadFixture('debugger_empty_config');
const diagnostics = await getDiagnostics('debugger.js');
Expand Down
17 changes: 16 additions & 1 deletion editors/vscode/tests/test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,29 @@ export async function loadFixture(fixture: string, workspaceDir: Uri = fixturesW
}

export async function getDiagnostics(file: string, workspaceDir: Uri = fixturesWorkspaceUri()): Promise<Diagnostic[]> {
const diagnostics = await getDiagnosticsWithoutClose(file, workspaceDir);
await commands.executeCommand('workbench.action.closeActiveEditor');
return diagnostics;
}

export async function getDiagnosticsWithoutClose(file: string, workspaceDir: Uri = fixturesWorkspaceUri()): Promise<Diagnostic[]> {
const fileUri = Uri.joinPath(workspaceDir, 'fixtures', file);
await window.showTextDocument(fileUri);
await sleep(500);
const diagnostics = languages.getDiagnostics(fileUri);
await commands.executeCommand('workbench.action.closeActiveEditor');
return diagnostics;
}

export async function writeToFixtureFile(file: string, content: string, workspaceDir: Uri = fixturesWorkspaceUri()): Promise<void> {
const fileUri = Uri.joinPath(workspaceDir, 'fixtures', file);
await window.showTextDocument(fileUri);

for (const char of content) {
await commands.executeCommand('type', { text: char });
await sleep(50);
}
}

export async function waitForDiagnosticChange(): Promise<void> {
return new Promise<void>((resolve) =>
languages.onDidChangeDiagnostics(() => {
Expand Down
Loading