diff --git a/crates/oxc_linter/src/rules/eslint/no_constructor_return.rs b/crates/oxc_linter/src/rules/eslint/no_constructor_return.rs index 468778b1ac7f3..1a63ac64f0d09 100644 --- a/crates/oxc_linter/src/rules/eslint/no_constructor_return.rs +++ b/crates/oxc_linter/src/rules/eslint/no_constructor_return.rs @@ -67,7 +67,7 @@ fn is_constructor(node: &AstNode<'_>) -> bool { fn is_definitely_in_constructor(ctx: &LintContext, node_id: NodeId) -> bool { ctx.nodes() - .ancestors(node_id) + .ancestor_ids(node_id) .map(|id| ctx.nodes().get_node(id)) .skip_while(|node| !node.kind().is_function_like()) .nth(1) diff --git a/crates/oxc_linter/src/rules/eslint/no_new.rs b/crates/oxc_linter/src/rules/eslint/no_new.rs index 858aae6c2d2c7..3282777ea6aae 100644 --- a/crates/oxc_linter/src/rules/eslint/no_new.rs +++ b/crates/oxc_linter/src/rules/eslint/no_new.rs @@ -36,7 +36,7 @@ impl Rule for NoNew { return; }; - let mut ancestors = ctx.nodes().ancestors(node.id()).skip(1); + let mut ancestors = ctx.nodes().ancestor_ids(node.id()).skip(1); let Some(node_id) = ancestors.next() else { return }; let kind = ctx.nodes().kind(node_id); diff --git a/crates/oxc_linter/src/rules/eslint/no_unsafe_finally.rs b/crates/oxc_linter/src/rules/eslint/no_unsafe_finally.rs index 65134a79c037e..13c3bc34f5af0 100644 --- a/crates/oxc_linter/src/rules/eslint/no_unsafe_finally.rs +++ b/crates/oxc_linter/src/rules/eslint/no_unsafe_finally.rs @@ -69,7 +69,7 @@ impl Rule for NoUnsafeFinally { let nodes = ctx.nodes(); let mut label_inside = false; - for node_id in nodes.ancestors(node.id()) { + for node_id in nodes.ancestor_ids(node.id()) { let ast_kind = nodes.kind(node_id); if sentinel_node_type.test(ast_kind) { diff --git a/crates/oxc_linter/src/rules/jest/no_duplicate_hooks.rs b/crates/oxc_linter/src/rules/jest/no_duplicate_hooks.rs index b576cda13be36..3991db6772eca 100644 --- a/crates/oxc_linter/src/rules/jest/no_duplicate_hooks.rs +++ b/crates/oxc_linter/src/rules/jest/no_duplicate_hooks.rs @@ -143,7 +143,7 @@ impl NoDuplicateHooks { let hook_name = jest_fn_call.name.to_string(); let parent_node_id = - match ctx.nodes().ancestors(node.id()).find(|n| hook_contexts.contains_key(n)) { + match ctx.nodes().ancestor_ids(node.id()).find(|n| hook_contexts.contains_key(n)) { Some(n) => Some(n), _ => Some(root_node_id), }; diff --git a/crates/oxc_linter/src/rules/nextjs/no_duplicate_head.rs b/crates/oxc_linter/src/rules/nextjs/no_duplicate_head.rs index 7e12541afead1..f6a978a62b596 100644 --- a/crates/oxc_linter/src/rules/nextjs/no_duplicate_head.rs +++ b/crates/oxc_linter/src/rules/nextjs/no_duplicate_head.rs @@ -79,7 +79,7 @@ impl Rule for NoDuplicateHead { } if !matches!( - nodes.ancestors(reference.node_id()).nth(2).map(|node_id| nodes.kind(node_id)), + nodes.ancestor_ids(reference.node_id()).nth(2).map(|node_id| nodes.kind(node_id)), Some(AstKind::JSXOpeningElement(_)) ) { continue; diff --git a/crates/oxc_linter/src/rules/oxc/bad_comparison_sequence.rs b/crates/oxc_linter/src/rules/oxc/bad_comparison_sequence.rs index 644ce1d3ab95a..de34b0aa5ef07 100644 --- a/crates/oxc_linter/src/rules/oxc/bad_comparison_sequence.rs +++ b/crates/oxc_linter/src/rules/oxc/bad_comparison_sequence.rs @@ -48,7 +48,7 @@ fn has_no_bad_comparison_in_parents<'a, 'b>( node: &'b AstNode<'a>, ctx: &'b LintContext<'a>, ) -> bool { - for node_id in ctx.nodes().ancestors(node.id()).skip(1) { + for node_id in ctx.nodes().ancestor_ids(node.id()).skip(1) { let kind = ctx.nodes().kind(node_id); // `a === b === c === d === e` only produce one error, since `(a === b === c) === d === e` will produce two errors. diff --git a/crates/oxc_linter/src/rules/oxc/missing_throw.rs b/crates/oxc_linter/src/rules/oxc/missing_throw.rs index b774f238774e3..5df24b9a06062 100644 --- a/crates/oxc_linter/src/rules/oxc/missing_throw.rs +++ b/crates/oxc_linter/src/rules/oxc/missing_throw.rs @@ -44,7 +44,7 @@ impl Rule for MissingThrow { impl MissingThrow { fn has_missing_throw<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>) -> bool { - let mut node_ancestors = ctx.nodes().ancestors(node.id()).skip(1); + let mut node_ancestors = ctx.nodes().ancestor_ids(node.id()).skip(1); let Some(node_id) = node_ancestors.next() else { return false; diff --git a/crates/oxc_linter/src/rules/promise/prefer_await_to_then.rs b/crates/oxc_linter/src/rules/promise/prefer_await_to_then.rs index 6775bf0982460..f2f6ce508a850 100644 --- a/crates/oxc_linter/src/rules/promise/prefer_await_to_then.rs +++ b/crates/oxc_linter/src/rules/promise/prefer_await_to_then.rs @@ -53,7 +53,7 @@ impl Rule for PreferAwaitToThen { // Already inside a yield or await if ctx .nodes() - .ancestors(node.id()) + .ancestor_ids(node.id()) .any(|node_id| is_inside_yield_or_await(ctx.nodes().get_node(node_id))) { return; diff --git a/crates/oxc_linter/src/rules/react/no_is_mounted.rs b/crates/oxc_linter/src/rules/react/no_is_mounted.rs index 2edd5f568ca0e..0b4b5d1e0db14 100644 --- a/crates/oxc_linter/src/rules/react/no_is_mounted.rs +++ b/crates/oxc_linter/src/rules/react/no_is_mounted.rs @@ -60,7 +60,7 @@ impl Rule for NoIsMounted { return; } - for ancestor in ctx.nodes().ancestors(node.id()).skip(1) { + for ancestor in ctx.nodes().ancestor_ids(node.id()).skip(1) { if matches!( ctx.nodes().kind(ancestor), AstKind::ObjectProperty(_) | AstKind::MethodDefinition(_) diff --git a/crates/oxc_linter/src/rules/react/rules_of_hooks.rs b/crates/oxc_linter/src/rules/react/rules_of_hooks.rs index 8d5d173e5ae1d..d01f8852b02cc 100644 --- a/crates/oxc_linter/src/rules/react/rules_of_hooks.rs +++ b/crates/oxc_linter/src/rules/react/rules_of_hooks.rs @@ -324,7 +324,10 @@ fn has_conditional_path_accept_throw( } fn parent_func<'a>(nodes: &'a AstNodes<'a>, node: &AstNode) -> Option<&'a AstNode<'a>> { - nodes.ancestors(node.id()).map(|id| nodes.get_node(id)).find(|it| it.kind().is_function_like()) + nodes + .ancestor_ids(node.id()) + .map(|id| nodes.get_node(id)) + .find(|it| it.kind().is_function_like()) } /// Checks if the `node_id` is a callback argument, @@ -346,7 +349,7 @@ fn is_non_react_func_arg(nodes: &AstNodes, node_id: NodeId) -> bool { fn is_somewhere_inside_component_or_hook(nodes: &AstNodes, node_id: NodeId) -> bool { nodes - .ancestors(node_id) + .ancestor_ids(node_id) .map(|id| nodes.get_node(id)) .filter(|node| node.kind().is_function_like()) .map(|node| { @@ -372,7 +375,7 @@ fn get_declaration_identifier<'a>( nodes: &'a AstNodes<'a>, node_id: NodeId, ) -> Option> { - nodes.ancestors(node_id).map(|id| nodes.kind(id)).find_map(|kind| { + nodes.ancestor_ids(node_id).map(|id| nodes.kind(id)).find_map(|kind| { match kind { // const useHook = () => {}; AstKind::VariableDeclaration(decl) if decl.declarations.len() == 1 => { @@ -399,7 +402,7 @@ fn get_declaration_identifier<'a>( fn is_export_default<'a>(nodes: &'a AstNodes<'a>, node_id: NodeId) -> bool { nodes - .ancestors(node_id) + .ancestor_ids(node_id) .map(|id| nodes.get_node(id)) .nth(1) .is_some_and(|node| matches!(node.kind(), AstKind::ExportDefaultDeclaration(_))) @@ -408,7 +411,7 @@ fn is_export_default<'a>(nodes: &'a AstNodes<'a>, node_id: NodeId) -> bool { /// # Panics /// `node_id` should always point to a valid `Function`. fn is_memo_or_forward_ref_callback(nodes: &AstNodes, node_id: NodeId) -> bool { - nodes.ancestors(node_id).map(|id| nodes.get_node(id)).any(|node| { + nodes.ancestor_ids(node_id).map(|id| nodes.get_node(id)).any(|node| { if let AstKind::CallExpression(call) = node.kind() { call.callee_name().is_some_and(|name| matches!(name, "forwardRef" | "memo")) } else { diff --git a/crates/oxc_linter/src/rules/typescript/explicit_function_return_type.rs b/crates/oxc_linter/src/rules/typescript/explicit_function_return_type.rs index 3281d198f7026..e4b39681a58ce 100644 --- a/crates/oxc_linter/src/rules/typescript/explicit_function_return_type.rs +++ b/crates/oxc_linter/src/rules/typescript/explicit_function_return_type.rs @@ -618,7 +618,7 @@ fn ancestor_has_return_type<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>) -> bo return false; } - for ancestor in ctx.nodes().ancestors(node.id()).skip(1) { + for ancestor in ctx.nodes().ancestor_ids(node.id()).skip(1) { match ctx.nodes().kind(ancestor) { AstKind::ArrowFunctionExpression(func) => { if func.return_type.is_some() { diff --git a/crates/oxc_linter/src/utils/react.rs b/crates/oxc_linter/src/utils/react.rs index cbaa4e3b49513..1fcd235c16849 100644 --- a/crates/oxc_linter/src/utils/react.rs +++ b/crates/oxc_linter/src/utils/react.rs @@ -195,7 +195,7 @@ pub fn get_parent_component<'a, 'b>( node: &'b AstNode<'a>, ctx: &'b LintContext<'a>, ) -> Option<&'b AstNode<'a>> { - for node_id in ctx.nodes().ancestors(node.id()) { + for node_id in ctx.nodes().ancestor_ids(node.id()) { let node = ctx.nodes().get_node(node_id); if is_es5_component(node) || is_es6_component(node) { return Some(node); diff --git a/crates/oxc_semantic/src/checker/javascript.rs b/crates/oxc_semantic/src/checker/javascript.rs index 78f595b179b6c..478265bc8f697 100644 --- a/crates/oxc_semantic/src/checker/javascript.rs +++ b/crates/oxc_semantic/src/checker/javascript.rs @@ -171,7 +171,7 @@ pub fn check_binding_identifier<'a>( // LexicalDeclaration : LetOrConst BindingList ; // * It is a Syntax Error if the BoundNames of BindingList contains "let". if !strict_mode && ident.name == "let" { - for node_id in ctx.nodes.ancestors(node.id()).skip(1) { + for node_id in ctx.nodes.ancestor_ids(node.id()).skip(1) { match ctx.nodes.kind(node_id) { AstKind::VariableDeclaration(decl) if decl.kind.is_lexical() => { return ctx.error(invalid_let_declaration(decl.kind.as_str(), ident.span)); @@ -197,7 +197,7 @@ pub fn check_identifier_reference<'a>( // Static Semantics: AssignmentTargetType // 1. If this IdentifierReference is contained in strict mode code and StringValue of Identifier is "eval" or "arguments", return invalid. if ctx.strict_mode() && matches!(ident.name.as_str(), "arguments" | "eval") { - for node_id in ctx.nodes.ancestors(node.id()).skip(1) { + for node_id in ctx.nodes.ancestor_ids(node.id()).skip(1) { match ctx.nodes.kind(node_id) { AstKind::AssignmentTarget(_) | AstKind::SimpleAssignmentTarget(_) => { return ctx.error(unexpected_identifier_assign(&ident.name, ident.span)); @@ -214,7 +214,7 @@ pub fn check_identifier_reference<'a>( // It is a Syntax Error if ContainsArguments of ClassStaticBlockStatementList is true. if ident.name == "arguments" { - for node_id in ctx.nodes.ancestors(node.id()).skip(1) { + for node_id in ctx.nodes.ancestor_ids(node.id()).skip(1) { match ctx.nodes.kind(node_id) { AstKind::Function(_) => break, AstKind::PropertyDefinition(_) => { @@ -567,7 +567,7 @@ pub fn check_break_statement<'a>( ctx: &SemanticBuilder<'a>, ) { // It is a Syntax Error if this BreakStatement is not nested, directly or indirectly (but not crossing function or static initialization block boundaries), within an IterationStatement or a SwitchStatement. - for node_id in ctx.nodes.ancestors(node.id()).skip(1) { + for node_id in ctx.nodes.ancestor_ids(node.id()).skip(1) { match ctx.nodes.kind(node_id) { AstKind::Program(_) => { return stmt.label.as_ref().map_or_else( @@ -613,7 +613,7 @@ pub fn check_continue_statement<'a>( ctx: &SemanticBuilder<'a>, ) { // It is a Syntax Error if this ContinueStatement is not nested, directly or indirectly (but not crossing function or static initialization block boundaries), within an IterationStatement. - for node_id in ctx.nodes.ancestors(node.id()).skip(1) { + for node_id in ctx.nodes.ancestor_ids(node.id()).skip(1) { match ctx.nodes.kind(node_id) { AstKind::Program(_) => { return stmt.label.as_ref().map_or_else( @@ -666,7 +666,7 @@ pub fn check_labeled_statement<'a>( node: &AstNode<'a>, ctx: &SemanticBuilder<'a>, ) { - for node_id in ctx.nodes.ancestors(node.id()).skip(1) { + for node_id in ctx.nodes.ancestor_ids(node.id()).skip(1) { match ctx.nodes.kind(node_id) { // label cannot cross boundary on function or static block AstKind::Function(_) | AstKind::StaticBlock(_) | AstKind::Program(_) => break, @@ -863,7 +863,7 @@ pub fn check_super<'a>(sup: &Super, node: &AstNode<'a>, ctx: &SemanticBuilder<'a // skip(1) is the self `Super` // skip(2) is the parent `CallExpression` or `NewExpression` - for node_id in ctx.nodes.ancestors(node.id()).skip(2) { + for node_id in ctx.nodes.ancestor_ids(node.id()).skip(2) { match ctx.nodes.kind(node_id) { AstKind::MethodDefinition(def) => { // ClassElement : MethodDefinition @@ -1094,7 +1094,7 @@ pub fn check_unary_expression<'a>( } fn is_in_formal_parameters<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) -> bool { - for node_id in ctx.nodes.ancestors(node.id()).skip(1) { + for node_id in ctx.nodes.ancestor_ids(node.id()).skip(1) { match ctx.nodes.kind(node_id) { AstKind::FormalParameter(_) => return true, AstKind::Program(_) | AstKind::Function(_) | AstKind::ArrowFunctionExpression(_) => { diff --git a/crates/oxc_semantic/src/node.rs b/crates/oxc_semantic/src/node.rs index 3fd50c69a00b4..6a6727431986d 100644 --- a/crates/oxc_semantic/src/node.rs +++ b/crates/oxc_semantic/src/node.rs @@ -220,7 +220,7 @@ impl<'a> AstNodes<'a> { /// pointed to by `node_id`. The last node will always be a [`Program`]. /// /// [`Program`]: oxc_ast::ast::Program - pub fn ancestors(&self, node_id: NodeId) -> impl Iterator + '_ { + pub fn ancestor_ids(&self, node_id: NodeId) -> impl Iterator + '_ { let parent_ids = &self.parent_ids; std::iter::successors(Some(node_id), |&node_id| parent_ids[node_id]) }