1#![doc = include_str!("../README.md")]
2#![allow(unused_assignments)] extern crate alloc;
5
6use std::time::Instant;
7
8use anyhow::Result;
9use bpaf::{Bpaf, ShellComp};
10use lintel_diagnostics::reporter::{CheckResult, Reporter};
11
12use lintel_cli_common::CliCacheOptions;
13
14pub mod catalog;
19pub mod parsers;
20pub mod registry;
21pub(crate) mod suggest;
22pub mod validate;
23
24#[derive(Debug, Clone, Bpaf)]
29pub struct ValidateArgs {
30 #[bpaf(long("exclude"), argument("PATTERN"))]
31 pub exclude: Vec<String>,
32
33 #[bpaf(external(lintel_cli_common::cli_cache_options))]
34 pub cache: CliCacheOptions,
35
36 #[bpaf(positional("PATH"), complete_shell(ShellComp::File { mask: None }))]
37 pub globs: Vec<String>,
38}
39
40impl From<&ValidateArgs> for validate::ValidateArgs {
41 fn from(args: &ValidateArgs) -> Self {
42 let config_dir = args
45 .globs
46 .iter()
47 .find(|g| std::path::Path::new(g).is_dir())
48 .map(std::path::PathBuf::from);
49
50 validate::ValidateArgs {
51 globs: args.globs.clone(),
52 exclude: args.exclude.clone(),
53 cache_dir: args.cache.cache_dir.clone(),
54 force_schema_fetch: args.cache.force_schema_fetch || args.cache.force,
55 force_validation: args.cache.force_validation || args.cache.force,
56 no_catalog: args.cache.no_catalog,
57 config_dir,
58 schema_cache_ttl: args.cache.schema_cache_ttl,
59 }
60 }
61}
62
63pub fn merge_config(args: &mut ValidateArgs) {
73 let search_dir = args
74 .globs
75 .iter()
76 .find(|g| std::path::Path::new(g).is_dir())
77 .map(std::path::PathBuf::from);
78
79 let cfg_result = match &search_dir {
80 Some(dir) => lintel_config::find_and_load(dir).map(Option::unwrap_or_default),
81 None => lintel_config::load(),
82 };
83
84 match cfg_result {
85 Ok(cfg) => {
86 let cli_excludes = core::mem::take(&mut args.exclude);
88 args.exclude = cfg.exclude;
89 args.exclude.extend(cli_excludes);
90 }
91 Err(e) => {
92 eprintln!("warning: failed to load lintel.toml: {e}");
93 }
94 }
95}
96
97pub async fn run(args: &mut ValidateArgs, reporter: &mut dyn Reporter) -> Result<bool> {
109 merge_config(args);
110
111 let lib_args = validate::ValidateArgs::from(&*args);
112 let start = Instant::now();
113 let result: CheckResult = validate::run_with(&lib_args, None, |file| {
114 reporter.on_file_checked(file);
115 })
116 .await?;
117 let had_errors = result.has_errors();
118 let elapsed = start.elapsed();
119
120 reporter.report(result, elapsed);
121
122 Ok(had_errors)
123}