diff --git a/crates/oxc_linter/src/context/mod.rs b/crates/oxc_linter/src/context/mod.rs index 75b5001b74d9f..5b43da25be559 100644 --- a/crates/oxc_linter/src/context/mod.rs +++ b/crates/oxc_linter/src/context/mod.rs @@ -148,6 +148,21 @@ impl<'a> LintContext<'a> { .map(|(a, _)| a as u32) } + /// Finds the next occurrence of the given token within a bounded span, + /// starting from the specified position, skipping over comments. + /// + /// Returns the offset from `start` if the token is found before `end`, + /// otherwise returns `None`. + #[expect(clippy::cast_possible_truncation)] + pub fn find_next_token_within(&self, start: u32, end: u32, token: &str) -> Option { + let source = self.source_range(Span::new(start, end)); + + 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/import/no_empty_named_blocks.rs b/crates/oxc_linter/src/rules/import/no_empty_named_blocks.rs index 85efda9a4724d..19b02ed8e588c 100644 --- a/crates/oxc_linter/src/rules/import/no_empty_named_blocks.rs +++ b/crates/oxc_linter/src/rules/import/no_empty_named_blocks.rs @@ -65,10 +65,17 @@ impl Rule for NoEmptyNamedBlocks { }; // import Default, {} from 'mod' - // Find the comma and "from" keyword, skipping any comments - let Some(comma_offset) = ctx.find_next_token_from(specifier.span.end, ",") else { return }; + let Some(comma_offset) = + ctx.find_next_token_within(specifier.span.end, import_decl.span.end, ",") + else { + return; + }; let comma_pos = specifier.span.end + comma_offset; - let Some(from_offset) = ctx.find_next_token_from(comma_pos, "from") else { return }; + + let Some(from_offset) = ctx.find_next_token_within(comma_pos, import_decl.span.end, "from") + else { + return; + }; let from_pos = comma_pos + from_offset; let start = specifier.span.end; @@ -94,6 +101,9 @@ fn test() { "import type Default, { Named } from 'mod'", "import type * as Namespace from 'mod'", "import * as Namespace from 'mod'", + r#" + import nodePath from "node:path"; a,"from"; + "#, ]; let fail = vec![