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