Skip to main content

react_auditor/rules/quality/
no_deep_nesting.rs

1use oxc_ast::ast::Program;
2use oxc_ast_visit::Visit;
3use oxc_ast_visit::walk::walk_statement;
4use oxc_semantic::Semantic;
5use oxc_span::GetSpan;
6
7use crate::rules::{Rule, RuleFinding, RuleMeta, Severity};
8
9pub struct NoDeepNesting;
10
11const RULE_META: RuleMeta = RuleMeta {
12    id: "no-deep-nesting",
13    default_severity: Severity::Warning,
14    category: "quality",
15    description: "Avoid nesting deeper than 4 levels",
16};
17
18const MAX_DEPTH: usize = 4;
19
20impl Rule for NoDeepNesting {
21    fn meta(&self) -> &RuleMeta {
22        &RULE_META
23    }
24
25    fn run(&self, program: &Program, _semantic: &Semantic, source_text: &str) -> Vec<RuleFinding> {
26        let mut collector = NestingCollector {
27            findings: Vec::new(),
28            source: source_text,
29            depth: 0,
30        };
31        collector.visit_program(program);
32        collector.findings
33    }
34}
35
36struct NestingCollector<'a> {
37    findings: Vec<RuleFinding>,
38    source: &'a str,
39    depth: usize,
40}
41
42impl<'a> Visit<'a> for NestingCollector<'a> {
43    fn visit_statement(&mut self, stmt: &oxc_ast::ast::Statement<'a>) {
44        let is_nesting = matches!(
45            stmt,
46            oxc_ast::ast::Statement::IfStatement(_)
47                | oxc_ast::ast::Statement::ForStatement(_)
48                | oxc_ast::ast::Statement::ForInStatement(_)
49                | oxc_ast::ast::Statement::ForOfStatement(_)
50                | oxc_ast::ast::Statement::WhileStatement(_)
51                | oxc_ast::ast::Statement::DoWhileStatement(_)
52                | oxc_ast::ast::Statement::SwitchStatement(_)
53        );
54
55        if is_nesting {
56            self.depth += 1;
57            if self.depth > MAX_DEPTH {
58                let start = stmt.span().start as usize;
59                let line = self.source[..start].lines().count().max(1);
60                let col = start - self.source[..start].rfind('\n').map(|i| i + 1).unwrap_or(0);
61
62                self.findings.push(RuleFinding {
63                    line,
64                    column: col + 1,
65                    message: format!(
66                        "Nesting depth {depth} exceeds max {MAX_DEPTH}",
67                        depth = self.depth
68                    ),
69                });
70            }
71            walk_statement(self, stmt);
72            self.depth -= 1;
73        } else {
74            walk_statement(self, stmt);
75        }
76    }
77}