1use std::path::PathBuf;
7
8use anyhow::Result;
9use console::style;
10
11use crate::schema;
12
13#[derive(Debug, Clone)]
15pub struct ValidateOptions {
16 pub file: PathBuf,
18}
19
20pub fn execute_validate(options: ValidateOptions) -> Result<()> {
22 let content = std::fs::read_to_string(&options.file)?;
23 let filename = options.file.to_string_lossy();
24
25 if let Some(schema_type) = schema::detect_schema_type(&filename) {
27 schema::validate_by_type(&content, schema_type)?;
28 println!(
29 "{} {} file is valid",
30 style("✓").green(),
31 schema_type.to_uppercase()
32 );
33 } else {
34 let json: serde_json::Value = match serde_json::from_str(&content) {
36 Ok(json) => json,
37 Err(e) => {
38 eprintln!("{} File is not valid JSON: {}", style("✗").red(), e);
39 eprintln!();
40 eprintln!("The validate command validates ACP JSON files:");
41 eprintln!(" - .acp/acp.cache.json (cache)");
42 eprintln!(" - .acp/acp.vars.json (vars)");
43 eprintln!(" - .acp.config.json (config)");
44 eprintln!(" - .acp/acp.attempts.json (attempts)");
45 eprintln!(" - sync files (sync)");
46 eprintln!(" - primer files (primer)");
47 eprintln!();
48 eprintln!("For source code validation, use: acp annotate --check");
49 std::process::exit(1);
50 }
51 };
52 if let Some(schema_url) = json.get("$schema").and_then(|s| s.as_str()) {
53 let detected = if schema_url.contains("cache") {
54 "cache"
55 } else if schema_url.contains("vars") {
56 "vars"
57 } else if schema_url.contains("config") {
58 "config"
59 } else if schema_url.contains("attempts") {
60 "attempts"
61 } else if schema_url.contains("sync") {
62 "sync"
63 } else if schema_url.contains("primer") {
64 "primer"
65 } else {
66 ""
67 };
68
69 if !detected.is_empty() {
70 schema::validate_by_type(&content, detected)?;
71 println!(
72 "{} {} file is valid",
73 style("✓").green(),
74 detected.to_uppercase()
75 );
76 } else {
77 eprintln!(
78 "{} Unknown schema type. Could not detect from filename or $schema field.",
79 style("✗").red()
80 );
81 std::process::exit(1);
82 }
83 } else {
84 eprintln!(
85 "{} Unknown file type. Provide filename with schema type (cache, vars, config, primer, attempts, sync) or include $schema field.",
86 style("✗").red()
87 );
88 std::process::exit(1);
89 }
90 }
91
92 Ok(())
93}