From 6102b1b8c83bf21007dfaccc5da93b961ace1bb7 Mon Sep 17 00:00:00 2001 From: alexion Date: Sat, 19 Sep 2026 17:31:50 -0400 Subject: [PATCH] docs(rust-style): order declarations by dependency --- src/skills/style/rust/rules/declarations.md | 38 +++++++ src/xatu/rules.rs | 28 ++--- src/xatu/xatu_main.rs | 114 ++++++++++---------- 3 files changed, 109 insertions(+), 71 deletions(-) create mode 100644 src/skills/style/rust/rules/declarations.md diff --git a/src/skills/style/rust/rules/declarations.md b/src/skills/style/rust/rules/declarations.md new file mode 100644 index 0000000..4e337c7 --- /dev/null +++ b/src/skills/style/rust/rules/declarations.md @@ -0,0 +1,38 @@ +# Declaration rules + +## Order declarations by dependency + +### Rule + +Order Rust declarations in depth-first dependency order. +Place each function, struct, and enum before private declarations that support it. +For structs and enums, order supporting declarations by field or variant order. +For functions, order helper declarations by first use in the function body. +Apply the same rule recursively to each supporting declaration. + +### Rationale + +Dependency order lets readers start at the public operation or type. +Readers can then continue downward into the declarations that explain each part. + +### Examples + +```rust +pub struct Report { + files: FileStore, + diagnostics: Vec, +} + +struct FileStore { + files: Vec, +} + +struct SourceFile { + path: PathBuf, + source: String, +} + +struct Diagnostic { + message: String, +} +``` diff --git a/src/xatu/rules.rs b/src/xatu/rules.rs index 94b7f05..068f921 100644 --- a/src/xatu/rules.rs +++ b/src/xatu/rules.rs @@ -38,20 +38,6 @@ pub trait NodeRule { fn check(node: &Self::Node) -> Option<&'static str>; } -fn run_node_rule(node: &ast::Node) -> Option -where - R: NodeRule, -{ - let typed_node = R::select(&node.data)?; - let message = R::check(typed_node)?; - - Some(Finding { - rule_id: R::ID, - range: node.range, - message, - }) -} - pub fn run_rules(file: &ast::ParsedFile) -> Vec { file.nodes .iter() @@ -69,3 +55,17 @@ pub fn run_rules(file: &ast::ParsedFile) -> Vec { }) .collect() } + +fn run_node_rule(node: &ast::Node) -> Option +where + R: NodeRule, +{ + let typed_node = R::select(&node.data)?; + let message = R::check(typed_node)?; + + Some(Finding { + rule_id: R::ID, + range: node.range, + message, + }) +} diff --git a/src/xatu/xatu_main.rs b/src/xatu/xatu_main.rs index 7e43fac..517d4e5 100644 --- a/src/xatu/xatu_main.rs +++ b/src/xatu/xatu_main.rs @@ -4,28 +4,45 @@ use std::path::{Path, PathBuf}; use std::process::ExitCode; use xatu::{Report, SourceFile}; -fn is_nix_file(path: &Path) -> bool { - path.extension().is_some_and(|extension| extension == "nix") +fn main() -> ExitCode { + match analyze(Args::parse()) { + Ok(report) if report.is_clean() => { + println!("No findings."); + ExitCode::SUCCESS + } + Ok(report) => { + print!("{report}"); + ExitCode::from(1) + } + Err(error) => { + eprintln!("{error}"); + ExitCode::from(2) + } + } } -// TODO: Add configurable exclusions. -fn is_excluded_dir(path: &Path) -> bool { - path.file_name() - .and_then(|name| name.to_str()) - .is_some_and(|name| { - matches!( - name, - ".git" - | "bazel-bin" - | "bazel-dev" - | "bazel-out" - | "bazel-testlogs" - | "target" - | "testdata" - | "third_party" - ) || name == "result" - || name.starts_with("result-") - }) +fn analyze(args: Args) -> status::Result { + let paths: Vec = args + .paths + .into_iter() + .map(monorepo::workspace::resolve_workspace_path) + .collect(); + + let files: Vec = paths + .iter() + .map(|path| collect_source_files(path)) + .collect::>>()? + .into_iter() + .flatten() + .collect(); + + xatu::future_sight(files) +} + +#[derive(Debug, Parser)] +struct Args { + #[arg(value_name = "PATH", default_value = ".")] + paths: Vec, } fn collect_source_files(path: &Path) -> status::Result> { @@ -61,43 +78,26 @@ fn collect_source_files(path: &Path) -> status::Result> { Ok(Vec::new()) } -#[derive(Debug, Parser)] -struct Args { - #[arg(value_name = "PATH", default_value = ".")] - paths: Vec, +// TODO: Add configurable exclusions. +fn is_excluded_dir(path: &Path) -> bool { + path.file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| { + matches!( + name, + ".git" + | "bazel-bin" + | "bazel-dev" + | "bazel-out" + | "bazel-testlogs" + | "target" + | "testdata" + | "third_party" + ) || name == "result" + || name.starts_with("result-") + }) } -fn analyze(args: Args) -> status::Result { - let paths: Vec = args - .paths - .into_iter() - .map(monorepo::workspace::resolve_workspace_path) - .collect(); - - let files: Vec = paths - .iter() - .map(|path| collect_source_files(path)) - .collect::>>()? - .into_iter() - .flatten() - .collect(); - - xatu::future_sight(files) -} - -fn main() -> ExitCode { - match analyze(Args::parse()) { - Ok(report) if report.is_clean() => { - println!("No findings."); - ExitCode::SUCCESS - } - Ok(report) => { - print!("{report}"); - ExitCode::from(1) - } - Err(error) => { - eprintln!("{error}"); - ExitCode::from(2) - } - } +fn is_nix_file(path: &Path) -> bool { + path.extension().is_some_and(|extension| extension == "nix") }