From 3778a6f65965b873c8f2de6d3cdafbd9ae2589a4 Mon Sep 17 00:00:00 2001 From: alexion Date: Thu, 17 Sep 2026 00:19:43 -0400 Subject: [PATCH] refactor(xatu): reduce scaffold to hello world Replace the initial parser prototype with a minimal hello-world skeleton so Xatu starts from a clean project shape before adding linter behavior. --- Cargo.lock | 4 -- src/xatu/BUILD | 6 +- src/xatu/Cargo.toml | 2 - src/xatu/lib.rs | 153 +------------------------------------------ src/xatu/lib_test.rs | 32 +-------- src/xatu/main.rs | 34 +--------- 6 files changed, 7 insertions(+), 224 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de37464..fec6a7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -302,10 +302,6 @@ dependencies = [ [[package]] name = "xatu" version = "0.1.0" -dependencies = [ - "clap", - "rnix", -] [[package]] name = "zmij" diff --git a/src/xatu/BUILD b/src/xatu/BUILD index 5ad8125..c51e802 100644 --- a/src/xatu/BUILD +++ b/src/xatu/BUILD @@ -4,17 +4,13 @@ rust_library( name = "xatu_lib", crate_name = "xatu", srcs = ["lib.rs"], - deps = ["//third_party/crates:rnix"], ) rust_binary( name = "xatu", crate_name = "xatu_cli", srcs = ["main.rs"], - deps = [ - ":xatu_lib", - "//third_party/crates:clap", - ], + deps = [":xatu_lib"], ) rust_test( diff --git a/src/xatu/Cargo.toml b/src/xatu/Cargo.toml index bf72d7e..fbe3e3a 100644 --- a/src/xatu/Cargo.toml +++ b/src/xatu/Cargo.toml @@ -15,5 +15,3 @@ name = "lib_test" path = "lib_test.rs" [dependencies] -clap = { version = "4", features = ["derive"] } -rnix = "0.14.0" diff --git a/src/xatu/lib.rs b/src/xatu/lib.rs index 5788637..e3fa985 100644 --- a/src/xatu/lib.rs +++ b/src/xatu/lib.rs @@ -1,152 +1,5 @@ -use std::fmt; -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; +pub const GREETING: &str = "Hello from Xatu"; -use rnix::ParseError; -pub type Result = std::result::Result; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Config { - pub paths: Vec, +pub fn greeting() -> &'static str { + GREETING } - -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct CheckReport { - diagnostics: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Diagnostic { - pub path: PathBuf, - pub line: usize, - pub column: usize, - pub rule: Rule, - pub message: String, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Rule { - ParseError, -} - -#[derive(Debug)] -pub enum Error { - Read { path: PathBuf, source: io::Error }, -} - -impl CheckReport { - pub fn diagnostics(&self) -> &[Diagnostic] { - &self.diagnostics - } - - pub fn has_diagnostics(&self) -> bool { - !self.diagnostics.is_empty() - } -} - -pub fn check(config: &Config) -> Result { - let mut report = CheckReport::default(); - - for path in &config.paths { - check_file(path, &mut report)?; - } - - Ok(report) -} - -pub fn check_source(path: impl Into, source: &str) -> CheckReport { - let path = path.into(); - let parsed = rnix::Root::parse(source); - let diagnostics = parsed - .errors() - .iter() - .map(|error| parse_diagnostic(&path, source, error)) - .collect(); - - CheckReport { diagnostics } -} - -fn check_file(path: &Path, report: &mut CheckReport) -> Result<()> { - let source = fs::read_to_string(path).map_err(|source| Error::Read { - path: path.to_path_buf(), - source, - })?; - - report - .diagnostics - .extend(check_source(path, &source).diagnostics); - Ok(()) -} - -fn parse_diagnostic(path: &Path, source: &str, error: &ParseError) -> Diagnostic { - let offset = parse_error_offset(error).unwrap_or(source.len()); - let (line, column) = line_column(source, offset); - - Diagnostic { - path: path.to_path_buf(), - line, - column, - rule: Rule::ParseError, - message: error.to_string(), - } -} - -fn parse_error_offset(error: &ParseError) -> Option { - match error { - ParseError::Unexpected(range) - | ParseError::UnexpectedExtra(range) - | ParseError::UnexpectedWanted(_, range, _) - | ParseError::UnexpectedDoubleBind(range) - | ParseError::DuplicatedArgs(range, _) => Some(range.start().into()), - ParseError::UnexpectedEOF - | ParseError::UnexpectedEOFWanted(_) - | ParseError::RecursionLimitExceeded => None, - _ => None, - } -} - -fn line_column(source: &str, offset: usize) -> (usize, usize) { - let bounded_offset = offset.min(source.len()); - let before = &source[..bounded_offset]; - let line = before.bytes().filter(|byte| *byte == b'\n').count() + 1; - let column = before - .rfind('\n') - .map_or(bounded_offset + 1, |newline| bounded_offset - newline); - - (line, column) -} - -impl fmt::Display for Diagnostic { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - formatter, - "{}:{}:{}: {}: {}", - self.path.display(), - self.line, - self.column, - self.rule, - self.message - ) - } -} - -impl fmt::Display for Rule { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Rule::ParseError => formatter.write_str("parse-error"), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::Read { path, source } => { - write!(formatter, "failed to read {}: {source}", path.display()) - } - } - } -} - -impl std::error::Error for Error {} diff --git a/src/xatu/lib_test.rs b/src/xatu/lib_test.rs index 607f438..d38e6d4 100644 --- a/src/xatu/lib_test.rs +++ b/src/xatu/lib_test.rs @@ -1,32 +1,4 @@ -use std::path::PathBuf; - -use xatu::{check_source, Rule}; - #[test] -fn valid_source_has_no_diagnostics() { - let report = check_source("valid.nix", "{ value = 1; }\n"); - - assert!(report.diagnostics().is_empty()); -} - -#[test] -fn invalid_source_reports_parse_error() { - let report = check_source("invalid.nix", "{ value = ; }\n"); - - assert!(!report.diagnostics().is_empty()); - let diagnostic = &report.diagnostics()[0]; - - assert_eq!(diagnostic.path, PathBuf::from("invalid.nix")); - assert_eq!(diagnostic.line, 1); - assert_eq!(diagnostic.rule, Rule::ParseError); - assert!(diagnostic.message.contains("unexpected")); -} - -#[test] -fn display_uses_compiler_style_shape() { - let report = check_source("invalid.nix", "{ value = ; }\n"); - let diagnostic = &report.diagnostics()[0]; - - assert!(diagnostic.to_string().starts_with("invalid.nix:1:")); - assert!(diagnostic.to_string().contains(": parse-error: ")); +fn greeting_returns_hello_message() { + assert_eq!(xatu::greeting(), "Hello from Xatu"); } diff --git a/src/xatu/main.rs b/src/xatu/main.rs index 38282a0..c532cbf 100644 --- a/src/xatu/main.rs +++ b/src/xatu/main.rs @@ -1,35 +1,3 @@ -use std::path::PathBuf; - -use clap::Parser; - -#[derive(Debug, Parser)] -struct Args { - #[arg(required = true)] - paths: Vec, -} - -impl From for xatu::Config { - fn from(args: Args) -> Self { - xatu::Config { paths: args.paths } - } -} - fn main() { - let config = xatu::Config::from(Args::parse()); - - match xatu::check(&config) { - Ok(report) => { - for diagnostic in report.diagnostics() { - println!("{diagnostic}"); - } - - if report.has_diagnostics() { - std::process::exit(1); - } - } - Err(error) => { - eprintln!("{error}"); - std::process::exit(2); - } - } + println!("{}", xatu::greeting()); }