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:");
75 eprintln!(" aperture docs # Interactive menu");
76 eprintln!(" aperture docs <api> # API overview");
77 eprintln!(" aperture docs <api> <tag> <operation> # Command help");
78 std::process::exit(1);
79 }
80 }
81 }
82 _ => {
83 eprintln!("Invalid help command arguments");
84 std::process::exit(1);
85 }
86 }
87 Ok(())
88}
89
90#[allow(clippy::too_many_lines)]
92pub fn execute_overview_command(
93 manager: &ConfigManager<OsFileSystem>,
94 api_name: Option<&str>,
95 all: bool,
96 output: &Output,
97) -> Result<(), Error> {
98 if !all {
99 let Some(api) = api_name else {
100 eprintln!("Error: Must specify API name or use --all flag");
101 eprintln!("Usage:");
102 eprintln!(" aperture overview <api>");
103 eprintln!(" aperture overview --all");
104 std::process::exit(1);
105 };
106 let specs = load_all_specs(manager)?;
107 let doc_gen = DocumentationGenerator::new(specs);
108 let overview = doc_gen.generate_api_overview(api)?;
109 println!("{overview}");
111 return Ok(());
112 }
113
114 let specs = load_all_specs(manager)?;
115 if specs.is_empty() {
116 output.info("No API specifications configured.");
117 output.info("Use 'aperture config add <name> <spec-file>' to get started.");
118 return Ok(());
119 }
120
121 println!("All APIs Overview\n");
123 println!("{}", "=".repeat(60));
125 for (api_name, spec) in &specs {
126 println!("\n** {} ** (v{})", spec.name, spec.version);
128 if let Some(ref base_url) = spec.base_url {
129 println!(" Base URL: {base_url}");
131 }
132 let operation_count = spec.commands.len();
133 println!(" Operations: {operation_count}");
135 let mut method_counts = std::collections::BTreeMap::new();
136 for command in &spec.commands {
137 *method_counts.entry(command.method.clone()).or_insert(0) += 1;
138 }
139 let method_summary: Vec<String> = method_counts
140 .iter()
141 .map(|(method, count)| format!("{method}: {count}"))
142 .collect();
143 println!(" Methods: {}", method_summary.join(", "));
145 println!(" Quick start: aperture list-commands {api_name}");
147 }
148 println!("\n{}", "=".repeat(60));
150 output.tip("Use 'aperture overview <api>' for detailed information about a specific API");
151 Ok(())
152}
153
154pub fn load_all_specs(
156 manager: &ConfigManager<OsFileSystem>,
157) -> Result<std::collections::BTreeMap<String, CachedSpec>, Error> {
158 let specs = manager.list_specs()?;
159 let cache_dir = manager.config_dir().join(constants::DIR_CACHE);
160 let mut all_specs = std::collections::BTreeMap::new();
161 for spec_name in &specs {
162 match loader::load_cached_spec(&cache_dir, spec_name) {
163 Ok(spec) => {
164 all_specs.insert(spec_name.clone(), spec);
165 }
166 Err(e) => eprintln!("Warning: Could not load spec '{spec_name}': {e}"),
167 }
168 }
169 Ok(all_specs)
170}