Skip to content

Commit 659fd37

Browse files
committed
feat(linter)!: tsgolint: request fixes when necessary (#15048)
With oxc-project/tsgolint#317, tsgolint fixes will become opt-in. So, we need to pass the `-fix` and `-fix-suggestions` when fixes are enabled in oxlint. @camc314 This will need to be added in oxlint with, or before switching to the next version of tsgolint.
1 parent e15c91c commit 659fd37

File tree

6 files changed

+87
-20
lines changed

6 files changed

+87
-20
lines changed

apps/oxlint/src/lint.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ impl CliRunner {
343343
let lint_runner = match LintRunner::builder(options, linter)
344344
.with_type_aware(self.options.type_aware)
345345
.with_silent(misc_options.silent)
346+
.with_fix_kind(fix_options.fix_kind())
346347
.build()
347348
{
348349
Ok(runner) => runner,

crates/oxc_language_server/src/linter/server_linter.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ impl ServerLinter {
179179
lint_on_run: options.run,
180180
diagnostics: ServerLinterDiagnostics::default(),
181181
tsgo_linter: if options.type_aware {
182-
Arc::new(Some(TsgoLinter::new(&root_path, config_store)))
182+
Arc::new(Some(TsgoLinter::new(&root_path, config_store, fix_kind)))
183183
} else {
184184
Arc::new(None)
185185
},
@@ -511,12 +511,16 @@ mod test {
511511
}
512512

513513
#[test]
514-
#[ignore = "Will be restored in #15048"]
515514
#[cfg(not(target_endian = "big"))]
516515
fn test_lint_on_run_on_type_on_save() {
517516
Tester::new(
518517
"fixtures/linter/lint_on_run/on_save",
519-
Some(LintOptions { type_aware: true, run: Run::OnType, ..Default::default() }),
518+
Some(LintOptions {
519+
type_aware: true,
520+
run: Run::OnType,
521+
fix_kind: LintFixKindFlag::All,
522+
..Default::default()
523+
}),
520524
)
521525
.test_and_snapshot_single_file_with_run_type("on-save.ts", Run::OnSave);
522526
}
@@ -532,12 +536,16 @@ mod test {
532536
}
533537

534538
#[test]
535-
#[ignore = "Will be restored in #15048"]
536539
#[cfg(not(target_endian = "big"))]
537540
fn test_lint_on_run_on_save_on_save() {
538541
Tester::new(
539542
"fixtures/linter/lint_on_run/on_type",
540-
Some(LintOptions { type_aware: true, run: Run::OnSave, ..Default::default() }),
543+
Some(LintOptions {
544+
type_aware: true,
545+
run: Run::OnSave,
546+
fix_kind: LintFixKindFlag::All,
547+
..Default::default()
548+
}),
541549
)
542550
.test_and_snapshot_single_file_with_run_type("on-save.ts", Run::OnSave);
543551
}
@@ -662,12 +670,16 @@ mod test {
662670
}
663671

664672
#[test]
665-
#[ignore = "Will be restored in #15048"]
666673
#[cfg(not(target_endian = "big"))] // TODO: tsgolint doesn't support big endian?
667674
fn test_tsgo_lint() {
668675
let tester = Tester::new(
669676
"fixtures/linter/tsgolint",
670-
Some(LintOptions { type_aware: true, run: Run::OnSave, ..Default::default() }),
677+
Some(LintOptions {
678+
type_aware: true,
679+
run: Run::OnSave,
680+
fix_kind: LintFixKindFlag::All,
681+
..Default::default()
682+
}),
671683
);
672684
tester.test_and_snapshot_single_file("no-floating-promises/index.ts");
673685
}

crates/oxc_language_server/src/linter/tsgo_linter.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::{
55

66
use oxc_data_structures::rope::Rope;
77
use oxc_linter::{
8-
ConfigStore, LINTABLE_EXTENSIONS, TsGoLintState, loader::LINT_PARTIAL_LOADER_EXTENSIONS,
9-
read_to_string,
8+
ConfigStore, FixKind, LINTABLE_EXTENSIONS, TsGoLintState,
9+
loader::LINT_PARTIAL_LOADER_EXTENSIONS, read_to_string,
1010
};
1111
use rustc_hash::FxHashSet;
1212
use tower_lsp_server::{UriExt, lsp_types::Uri};
@@ -20,8 +20,8 @@ pub struct TsgoLinter {
2020
}
2121

2222
impl TsgoLinter {
23-
pub fn new(root_uri: &Path, config_store: ConfigStore) -> Self {
24-
let state = TsGoLintState::new(root_uri, config_store);
23+
pub fn new(root_uri: &Path, config_store: ConfigStore, fix_kind: FixKind) -> Self {
24+
let state = TsGoLintState::new(root_uri, config_store, fix_kind);
2525
Self { state }
2626
}
2727

crates/oxc_linter/src/lint_runner.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use oxc_diagnostics::{DiagnosticSender, DiagnosticService};
1010
use oxc_span::Span;
1111

1212
use crate::{
13-
AllowWarnDeny, DisableDirectives, LintService, LintServiceOptions, Linter, TsGoLintState,
13+
AllowWarnDeny, DisableDirectives, FixKind, LintService, LintServiceOptions, Linter,
14+
TsGoLintState,
1415
};
1516

1617
/// Unified runner that orchestrates both regular (oxc) and type-aware (tsgolint) linting
@@ -129,6 +130,7 @@ pub struct LintRunnerBuilder {
129130
type_aware_enabled: bool,
130131
lint_service_options: LintServiceOptions,
131132
silent: bool,
133+
fix_kind: FixKind,
132134
}
133135

134136
impl LintRunnerBuilder {
@@ -138,6 +140,7 @@ impl LintRunnerBuilder {
138140
type_aware_enabled: false,
139141
lint_service_options,
140142
silent: false,
143+
fix_kind: FixKind::None,
141144
}
142145
}
143146

@@ -153,6 +156,12 @@ impl LintRunnerBuilder {
153156
self
154157
}
155158

159+
#[must_use]
160+
pub fn with_fix_kind(mut self, fix_kind: FixKind) -> Self {
161+
self.fix_kind = fix_kind;
162+
self
163+
}
164+
156165
/// # Errors
157166
/// Returns an error if the type-aware linter fails to initialize.
158167
pub fn build(self) -> Result<LintRunner, String> {
@@ -162,6 +171,7 @@ impl LintRunnerBuilder {
162171
match TsGoLintState::try_new(
163172
self.lint_service_options.cwd(),
164173
self.regular_linter.config.clone(),
174+
self.fix_kind,
165175
) {
166176
Ok(state) => Some(state.with_silent(self.silent)),
167177
Err(e) => return Err(e),

crates/oxc_linter/src/tsgolint.rs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use oxc_span::{SourceType, Span};
1414

1515
use super::{AllowWarnDeny, ConfigStore, DisableDirectives, ResolvedLinterState, read_to_string};
1616

17+
use crate::FixKind;
1718
#[cfg(feature = "language_server")]
1819
use crate::fixer::{CompositeFix, Message, PossibleFixes};
1920

@@ -29,24 +30,46 @@ pub struct TsGoLintState {
2930
/// If `oxlint` will output the diagnostics or not.
3031
/// When `silent` is true, we do not need to access the file system for nice diagnostics messages.
3132
silent: bool,
33+
/// If `true`, request that fixes be returned from `tsgolint`.
34+
fix: bool,
35+
/// If `true`, request that suggestions be returned from `tsgolint`.
36+
fix_suggestions: bool,
3237
}
3338

3439
impl TsGoLintState {
35-
pub fn new(cwd: &Path, config_store: ConfigStore) -> Self {
40+
pub fn new(cwd: &Path, config_store: ConfigStore, fix_kind: FixKind) -> Self {
3641
let executable_path =
3742
try_find_tsgolint_executable(cwd).unwrap_or(PathBuf::from("tsgolint"));
3843

39-
TsGoLintState { config_store, executable_path, cwd: cwd.to_path_buf(), silent: false }
44+
TsGoLintState {
45+
config_store,
46+
executable_path,
47+
cwd: cwd.to_path_buf(),
48+
silent: false,
49+
fix: fix_kind.contains(FixKind::Fix),
50+
fix_suggestions: fix_kind.contains(FixKind::Suggestion),
51+
}
4052
}
4153

4254
/// Try to create a new TsGoLintState, returning an error if the executable cannot be found.
4355
///
4456
/// # Errors
4557
/// Returns an error if the tsgolint executable cannot be found.
46-
pub fn try_new(cwd: &Path, config_store: ConfigStore) -> Result<Self, String> {
58+
pub fn try_new(
59+
cwd: &Path,
60+
config_store: ConfigStore,
61+
fix_kind: FixKind,
62+
) -> Result<Self, String> {
4763
let executable_path = try_find_tsgolint_executable(cwd)?;
4864

49-
Ok(TsGoLintState { config_store, executable_path, cwd: cwd.to_path_buf(), silent: false })
65+
Ok(TsGoLintState {
66+
config_store,
67+
executable_path,
68+
cwd: cwd.to_path_buf(),
69+
silent: false,
70+
fix: fix_kind.contains(FixKind::Fix),
71+
fix_suggestions: fix_kind.contains(FixKind::Suggestion),
72+
})
5073
}
5174

5275
/// Set to `true` to skip file system reads.
@@ -90,6 +113,14 @@ impl TsGoLintState {
90113
.stdout(std::process::Stdio::piped())
91114
.stderr(stderr());
92115

116+
if self.fix {
117+
cmd.arg("-fix");
118+
}
119+
120+
if self.fix_suggestions {
121+
cmd.arg("-fix-suggestions");
122+
}
123+
93124
if let Ok(trace_file) = std::env::var("OXLINT_TSGOLINT_TRACE") {
94125
cmd.arg(format!("-trace={trace_file}"));
95126
}
@@ -298,12 +329,23 @@ impl TsGoLintState {
298329
let json_input = self.json_input(std::slice::from_ref(path), &mut resolved_configs);
299330
let executable_path = self.executable_path.clone();
300331

332+
let fix = self.fix;
333+
let fix_suggestions = self.fix_suggestions;
301334
let handler = std::thread::spawn(move || {
302-
let child = std::process::Command::new(&executable_path)
303-
.arg("headless")
335+
let mut cmd = std::process::Command::new(&executable_path);
336+
cmd.arg("headless")
304337
.stdin(std::process::Stdio::piped())
305-
.stdout(std::process::Stdio::piped())
306-
.spawn();
338+
.stdout(std::process::Stdio::piped());
339+
340+
if fix {
341+
cmd.arg("-fix");
342+
}
343+
344+
if fix_suggestions {
345+
cmd.arg("-fix-suggestions");
346+
}
347+
348+
let child = cmd.spawn();
307349

308350
let mut child = match child {
309351
Ok(c) => c,

editors/vscode/tests/e2e_server.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ suite('E2E Diagnostics', () => {
265265
await loadFixture('type_aware');
266266
const firstDiagnostics = await getDiagnostics('index.ts');
267267

268+
await workspace.getConfiguration('oxc').update('fixKind', 'all');
269+
268270
strictEqual(firstDiagnostics.length, 0);
269271

270272
await workspace.getConfiguration('oxc').update('typeAware', true);

0 commit comments

Comments
 (0)