From e41dee549f9b7473734331fc4794b0c2b8e7f201 Mon Sep 17 00:00:00 2001 From: camc314 <18101008+camc314@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:52:24 +0000 Subject: [PATCH] fix(linter/consistent-type-definition): skip comments when looking for token (#14909) fixes #14833 --- crates/oxc_linter/src/context/mod.rs | 13 +++++++++++++ .../typescript/consistent_type_definitions.rs | 14 ++++++++------ .../typescript_consistent_type_definitions.snap | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/crates/oxc_linter/src/context/mod.rs b/crates/oxc_linter/src/context/mod.rs index b14e112eb1e81..d72c72c179c49 100644 --- a/crates/oxc_linter/src/context/mod.rs +++ b/crates/oxc_linter/src/context/mod.rs @@ -135,6 +135,19 @@ impl<'a> LintContext<'a> { span.source_text(self.parent.semantic().source_text()) } + /// Finds the next occurrence of the given token in the source code, + /// starting from the specified position, skipping over comments. + #[expect(clippy::cast_possible_truncation)] + pub fn find_next_token_from(&self, start: u32, token: &str) -> Option { + let source = + self.source_range(Span::new(start, self.parent.semantic().source_text().len() as u32)); + + source + .match_indices(token) + .find(|(a, _)| !self.is_inside_comment(start + *a as u32)) + .map(|(a, _)| a as u32) + } + /// Path to the file currently being linted. #[inline] pub fn file_path(&self) -> &Path { diff --git a/crates/oxc_linter/src/rules/typescript/consistent_type_definitions.rs b/crates/oxc_linter/src/rules/typescript/consistent_type_definitions.rs index 3e09ebe369157..04a1d4c9a1bd8 100644 --- a/crates/oxc_linter/src/rules/typescript/consistent_type_definitions.rs +++ b/crates/oxc_linter/src/rules/typescript/consistent_type_definitions.rs @@ -117,9 +117,9 @@ impl Rule for ConsistentTypeDefinitions { { let start = if decl.declare { let base_start = decl.span.start + 7; - ctx.source_range(Span::new(base_start, decl.span.end)) - .find("type") - .map_or(base_start + 1, |v| u32::try_from(v).unwrap_or(0) + base_start) + + ctx.find_next_token_from(base_start, "type") + .map_or(base_start + 1, |v| v + base_start) } else { decl.span.start }; @@ -201,9 +201,9 @@ impl Rule for ConsistentTypeDefinitions { { let start = if decl.declare { let base_start = decl.span.start + 7; - ctx.source_range(Span::new(base_start, decl.span.end)) - .find("interface") - .map_or(base_start + 1, |v| u32::try_from(v).unwrap_or(0) + base_start) + + ctx.find_next_token_from(base_start, "interface") + .map_or(base_start + 1, |v| v + base_start) } else { decl.span.start }; @@ -383,6 +383,8 @@ fn test() { ("declare…interface S {}", Some(serde_json::json!(["type"]))), ("export declare…type S={}", Some(serde_json::json!(["interface"]))), ("export declare…interface S {}", Some(serde_json::json!(["type"]))), + ("declare /* interface */ interface T { x: number; };", Some(serde_json::json!(["type"]))), + ("declare /* type */ type T = { x: number; };", Some(serde_json::json!(["interface"]))), ]; let fix = vec![ diff --git a/crates/oxc_linter/src/snapshots/typescript_consistent_type_definitions.snap b/crates/oxc_linter/src/snapshots/typescript_consistent_type_definitions.snap index b0489c1b8f04e..a7863e3c649a0 100644 --- a/crates/oxc_linter/src/snapshots/typescript_consistent_type_definitions.snap +++ b/crates/oxc_linter/src/snapshots/typescript_consistent_type_definitions.snap @@ -174,3 +174,17 @@ source: crates/oxc_linter/src/tester.rs · ───────── ╰──── help: Use an `type` instead of a `interface` + + ⚠ typescript-eslint(consistent-type-definitions): Use an `type` instead of a `interface` + ╭─[consistent_type_definitions.tsx:1:25] + 1 │ declare /* interface */ interface T { x: number; }; + · ───────── + ╰──── + help: Use an `type` instead of a `interface` + + ⚠ typescript-eslint(consistent-type-definitions): Use an `interface` instead of a `type` + ╭─[consistent_type_definitions.tsx:1:20] + 1 │ declare /* type */ type T = { x: number; }; + · ──── + ╰──── + help: Use an `interface` instead of a `type`