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
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"rules": {
"no-unused-expressions": "off",
"@typescript-eslint/no-floating-promises": "error"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Test file for disable directives with type-aware rules
const myPromise = new Promise(() => {})

// Test oxlint-disable-next-line
// oxlint-disable-next-line typescript/no-floating-promises
myPromise

// Test eslint-disable-next-line with @typescript-eslint prefix
// eslint-disable-next-line @typescript-eslint/no-floating-promises
myPromise

// Test oxlint-disable/enable block
/* oxlint-disable typescript/no-floating-promises */
myPromise
myPromise
/* oxlint-enable typescript/no-floating-promises */

// This should still report an error (no disable directive)
myPromise

// Test with different rule name formats
// oxlint-disable-next-line no-floating-promises
myPromise

// eslint-disable-next-line typescript-eslint/no-floating-promises
myPromise

// Test disable-line variant
myPromise // oxlint-disable-line typescript/no-floating-promises

// Multiple promises in one block
/* eslint-disable @typescript-eslint/no-floating-promises */
Promise.resolve(1)
Promise.resolve(2)
Promise.resolve(3)
/* eslint-enable @typescript-eslint/no-floating-promises */

// Should report error
Promise.resolve(4)
13 changes: 13 additions & 0 deletions crates/oxc_language_server/src/linter/server_linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,19 @@ mod test {
.test_and_snapshot_single_file("test.js");
}

#[test]
fn test_report_tsgolint_unused_directives() {
Tester::new(
"fixtures/linter/tsgolint/unused_disabled_directives",
Some(LintOptions {
unused_disable_directives: UnusedDisableDirectives::Deny,
type_aware: true,
..Default::default()
}),
)
.test_and_snapshot_single_file("test.ts");
}

#[test]
fn test_root_ignore_patterns() {
let tester = Tester::new("fixtures/linter/ignore_patterns", None);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
source: crates/oxc_language_server/src/tester.rs
---
##########
file: fixtures/linter/tsgolint/unused_disabled_directives/test.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: 18, character: 0 }, end: Position { line: 18, character: 9 } }
related_information[0].message: ""
related_information[0].location.uri: "file://<variable>/fixtures/linter/tsgolint/unused_disabled_directives/test.ts"
related_information[0].location.range: Range { start: Position { line: 18, character: 0 }, end: Position { line: 18, character: 9 } }
severity: Some(Error)
source: Some("oxc")
tags: None
fixed: Multiple(
[
FixedContent {
message: Some(
"Disable no-floating-promises for this line",
),
code: "// oxlint-disable-next-line no-floating-promises\n",
range: Range {
start: Position {
line: 18,
character: 0,
},
end: Position {
line: 18,
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,
},
},
},
],
)


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: 38, character: 0 }, end: Position { line: 38, character: 18 } }
related_information[0].message: ""
related_information[0].location.uri: "file://<variable>/fixtures/linter/tsgolint/unused_disabled_directives/test.ts"
related_information[0].location.range: Range { start: Position { line: 38, character: 0 }, end: Position { line: 38, character: 18 } }
severity: Some(Error)
source: Some("oxc")
tags: None
fixed: Multiple(
[
FixedContent {
message: Some(
"Disable no-floating-promises for this line",
),
code: "// oxlint-disable-next-line no-floating-promises\n",
range: Range {
start: Position {
line: 38,
character: 0,
},
end: Position {
line: 38,
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,
},
},
},
],
)
3 changes: 2 additions & 1 deletion crates/oxc_linter/src/lint_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ impl LintRunner {
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)
&& let Ok(tso_messages) =
type_aware_linter.lint_source(file, source_text, self.directives_store.map())
{
messages.extend(tso_messages);
}
Expand Down
70 changes: 37 additions & 33 deletions crates/oxc_linter/src/tsgolint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,39 +202,11 @@ impl TsGoLintState {
continue;
};

let span = Span::new(
tsgolint_diagnostic.range.pos,
tsgolint_diagnostic.range.end,
);

let should_skip = {
if let Some(directives) = disable_directives_map.get(&path)
{
directives.contains(&tsgolint_diagnostic.rule, span)
|| directives.contains(
&format!(
"typescript-eslint/{}",
tsgolint_diagnostic.rule
),
span,
)
|| directives.contains(
&format!(
"@typescript-eslint/{}",
tsgolint_diagnostic.rule
),
span,
)
} else {
debug_assert!(
false,
"disable_directives_map should have an entry for every file we linted"
);
false
}
};

if should_skip {
if should_skip_diagnostic(
&disable_directives_map,
&path,
&tsgolint_diagnostic,
) {
continue;
}

Expand Down Expand Up @@ -362,6 +334,7 @@ impl TsGoLintState {
&self,
path: &Arc<OsStr>,
source_text: String,
disable_directives_map: Arc<Mutex<FxHashMap<PathBuf, DisableDirectives>>>,
) -> Result<Vec<Message>, String> {
let mut resolved_configs: FxHashMap<PathBuf, ResolvedLinterState> = FxHashMap::default();
let mut source_overrides = FxHashMap::default();
Expand Down Expand Up @@ -420,6 +393,8 @@ impl TsGoLintState {
let stdout = child.stdout.take().expect("Failed to open tsgolint stdout");

let stdout_handler = std::thread::spawn(move || -> Result<Vec<Message>, String> {
let disable_directives_map =
disable_directives_map.lock().expect("disable_directives_map mutex poisoned");
let msg_iter = TsGoLintMessageStream::new(stdout);

let mut result = vec![];
Expand Down Expand Up @@ -452,6 +427,14 @@ impl TsGoLintState {
continue;
};

if should_skip_diagnostic(
&disable_directives_map,
&path,
&tsgolint_diagnostic,
) {
continue;
}

let mut message = Message::from_tsgo_lint_diagnostic(
tsgolint_diagnostic,
&source_text,
Expand Down Expand Up @@ -914,6 +897,27 @@ impl std::fmt::Display for TsGoLintMessageParseError {
}
}

fn should_skip_diagnostic(
disable_directives_map: &FxHashMap<PathBuf, DisableDirectives>,
path: &Path,
tsgolint_diagnostic: &TsGoLintRuleDiagnostic,
) -> bool {
let span = Span::new(tsgolint_diagnostic.range.pos, tsgolint_diagnostic.range.end);

if let Some(directives) = disable_directives_map.get(path) {
directives.contains(&tsgolint_diagnostic.rule, span)
|| directives.contains(&format!("typescript-eslint/{}", tsgolint_diagnostic.rule), span)
|| directives
.contains(&format!("@typescript-eslint/{}", tsgolint_diagnostic.rule), span)
} else {
debug_assert!(
false,
"disable_directives_map should have an entry for every file we linted"
);
false
}
}

/// Parses a single message from the binary tsgolint output.
// Messages are encoded as follows:
// | Payload Size (uint32 LE) - 4 bytes | Message Type (uint8) - 1 byte | Payload |
Expand Down
Loading