aperture_cli/cli/commands/
docs.rs1use crate::cache::models::CachedSpec;
4use crate::config::manager::{get_config_dir, ConfigManager};
5use crate::constants;
6use crate::docs::{DocumentationGenerator, HelpFormatter};
7use crate::engine::loader;
8use crate::error::Error;
9use crate::fs::OsFileSystem;
10use crate::output::Output;
11use std::path::PathBuf;
12
13pub fn list_commands(context: &str, output: &Output) -> Result<(), Error> {
14 let config_dir = if let Ok(dir) = std::env::var(constants::ENV_APERTURE_CONFIG_DIR) {
15 PathBuf::from(dir)
16 } else {
17 get_config_dir()?
18 };
19 let cache_dir = config_dir.join(constants::DIR_CACHE);
20 let spec = loader::load_cached_spec(&cache_dir, context).map_err(|e| match e {
21 Error::Io(_) => Error::spec_not_found(context),
22 _ => e,
23 })?;
24 let formatted_output = HelpFormatter::format_command_list(&spec);
25 println!("{formatted_output}");
27 output.tip(format!(
28 "Use 'aperture docs {context}' for detailed API documentation"
29 ));
30 output.tip(format!(
31 "Use 'aperture search <term> --api {context}' to find specific operations"
32 ));
33 output.tip("Use shortcuts: 'aperture exec <operation-id> --help'");
34 Ok(())
35}
36
37pub fn execute_help_command(
39 manager: &ConfigManager<OsFileSystem>,
40 api_name: Option<&str>,
41 tag: Option<&str>,
42 operation: Option<&str>,
43 enhanced: bool,
44 output: &Output,
45) -> Result<(), Error> {
46 match (api_name, tag, operation) {
47 (None, None, None) => {
48 let specs = load_all_specs(manager)?;
49 let doc_gen = DocumentationGenerator::new(specs);
50 println!("{}", doc_gen.generate_interactive_menu());
52 }
53 (Some(api), tag_opt, operation_opt) => {
54 let specs = load_all_specs(manager)?;
55 let doc_gen = DocumentationGenerator::new(specs);
56 match (tag_opt, operation_opt) {
57 (None, None) => {
58 let overview = doc_gen.generate_api_overview(api)?;
59 println!("{overview}");
61 }
62 (Some(tag), Some(op)) => {
63 let help = doc_gen.generate_command_help(api, tag, op)?;
64 if enhanced {
65 println!("{help}");
67 } else {
68 println!("{}", help.lines().take(20).collect::<Vec<_>>().join("\n"));
70 output.tip("Use --enhanced for full documentation with examples");
71 }
72 }
73 _ => {
74 eprintln!("Invalid docs command. Usage:");
77 eprintln!(" aperture docs # Interactive menu");
79 eprintln!(" aperture docs <api> # API overview");
81 eprintln!(" aperture docs <api> <tag> <operation> # Command help");
83 std::process::exit(1);
84 }
85 }
86 }
87 _ => {
88 eprintln!("Invalid help command arguments");
91 std::process::exit(1);
92 }
93 }
94 Ok(())
95}
96
97#[allow(clippy::too_many_lines)]
99pub fn execute_overview_command(
100 manager: &ConfigManager<OsFileSystem>,
101 api_name: Option<&str>,
102 all: bool,
103 output: &Output,
104) -> Result<(), Error> {
105 if !all {
106 let Some(api) = api_name else {
107 eprintln!("Error: Must specify API name or use --all flag");
110 eprintln!("Usage:");
112 eprintln!(" aperture overview <api>");
114 eprintln!(" aperture overview --all");
116 std::process::exit(1);
117 };
118 let specs = load_all_specs(manager)?;
119 let doc_gen = DocumentationGenerator::new(specs);
120 let overview = doc_gen.generate_api_overview(api)?;
121 println!("{overview}");
123 return Ok(());
124 }
125
126 let specs = load_all_specs(manager)?;
127 if specs.is_empty() {
128 output.info("No API specifications configured.");
129 output.info("Use 'aperture config add <name> <spec-file>' to get started.");
130 return Ok(());
131 }
132
133 println!("All APIs Overview\n");
135 println!("{}", "=".repeat(60));
137 for (api_name, spec) in &specs {
138 println!("\n** {} ** (v{})", spec.name, spec.version);
140 if let Some(ref base_url) = spec.base_url {
141 println!(" Base URL: {base_url}");
143 }
144 let operation_count = spec.commands.len();
145 println!(" Operations: {operation_count}");
147 let mut method_counts = std::collections::BTreeMap::new();
148 for command in &spec.commands {
149 *method_counts.entry(command.method.clone()).or_insert(0) += 1;
150 }
151 let method_summary: Vec<String> = method_counts
152 .iter()
153 .map(|(method, count)| format!("{method}: {count}"))
154 .collect();
155 println!(" Methods: {}", method_summary.join(", "));
157 println!(" Quick start: aperture list-commands {api_name}");
159 }
160 println!("\n{}", "=".repeat(60));
162 output.tip("Use 'aperture overview <api>' for detailed information about a specific API");
163 Ok(())
164}
165
166pub fn load_all_specs(
168 manager: &ConfigManager<OsFileSystem>,
169) -> Result<std::collections::BTreeMap<String, CachedSpec>, Error> {
170 let specs = manager.list_specs()?;
171 let cache_dir = manager.config_dir().join(constants::DIR_CACHE);
172 let mut all_specs = std::collections::BTreeMap::new();
173 for spec_name in &specs {
174 match loader::load_cached_spec(&cache_dir, spec_name) {
175 Ok(spec) => {
176 all_specs.insert(spec_name.clone(), spec);
177 }
178 Err(e) => tracing::warn!(spec = spec_name, error = %e, "could not load spec"),
179 }
180 }
181 Ok(all_specs)
182}