vika_cli/commands/
init.rs1use crate::config::loader::save_config;
2use crate::config::model::Config;
3use crate::config::validator::validate_config;
4use crate::error::{GenerationError, Result};
5use crate::generator::writer::{ensure_directory, write_http_client_template};
6use colored::*;
7use dialoguer::{Confirm, Input, Select};
8use std::path::PathBuf;
9
10pub fn run() -> Result<()> {
11 println!("{}", "Initializing vika-cli project...".bright_cyan());
12 println!();
13
14 let config_path = PathBuf::from(".vika.json");
16 if config_path.exists() {
17 println!(
18 "{}",
19 "⚠️ .vika.json already exists. Skipping config creation.".yellow()
20 );
21 } else {
22 println!(
23 "{}",
24 "Let's configure your vika-cli preferences:".bright_cyan()
25 );
26 println!();
27
28 println!("{}", "📁 Paths Configuration".bright_yellow());
30 println!();
31
32 let root_dir: String = Input::new()
33 .with_prompt("Root directory for generated code")
34 .default("src".to_string())
35 .interact_text()
36 .map_err(|e| GenerationError::InvalidOperation {
37 message: format!("Failed to get user input: {}", e),
38 })?;
39
40 println!();
41
42 let schemas_output: String = Input::new()
43 .with_prompt("Schemas output directory")
44 .default("src/schemas".to_string())
45 .interact_text()
46 .map_err(|e| GenerationError::InvalidOperation {
47 message: format!("Failed to get user input: {}", e),
48 })?;
49
50 println!();
51
52 let apis_output: String = Input::new()
53 .with_prompt("APIs output directory")
54 .default("src/apis".to_string())
55 .interact_text()
56 .map_err(|e| GenerationError::InvalidOperation {
57 message: format!("Failed to get user input: {}", e),
58 })?;
59
60 println!();
61
62 let naming_options = ["PascalCase", "camelCase", "snake_case", "kebab-case"];
64 let naming_index = Select::new()
65 .with_prompt("Schema naming convention")
66 .items(&[
67 "PascalCase - ProductDto, UserProfile (recommended)",
68 "camelCase - productDto, userProfile",
69 "snake_case - product_dto, user_profile",
70 "kebab-case - product-dto, user-profile",
71 ])
72 .default(0)
73 .interact()
74 .map_err(|e| GenerationError::InvalidOperation {
75 message: format!("Failed to get user selection: {}", e),
76 })?;
77
78 let naming = naming_options[naming_index].to_string();
79
80 println!();
81
82 println!("{}", "🔌 API Configuration".bright_yellow());
84 println!();
85
86 let api_style_options = ["fetch"];
87 let api_style_index = Select::new()
88 .with_prompt("API client style")
89 .items(&["fetch - Native Fetch API (recommended)"])
90 .default(0)
91 .interact()
92 .map_err(|e| GenerationError::InvalidOperation {
93 message: format!("Failed to get user selection: {}", e),
94 })?;
95
96 let api_style = api_style_options[api_style_index].to_string();
97
98 println!();
99
100 let base_url_input: String = Input::new()
101 .with_prompt("API base URL (optional, press Enter to skip)")
102 .allow_empty(true)
103 .interact_text()
104 .map_err(|e| GenerationError::InvalidOperation {
105 message: format!("Failed to get user input: {}", e),
106 })?;
107
108 let base_url = if base_url_input.trim().is_empty() {
109 None
110 } else {
111 Some(base_url_input.trim().to_string())
112 };
113
114 println!();
115
116 let header_strategy_options = ["consumerInjected", "bearerToken", "fixed"];
117 let header_strategy_index = Select::new()
118 .with_prompt("Header strategy for API requests")
119 .items(&[
120 "consumerInjected - Headers provided by consumer (recommended)",
121 "bearerToken - Automatic Bearer token injection",
122 "fixed - Fixed headers from config",
123 ])
124 .default(0)
125 .interact()
126 .map_err(|e| GenerationError::InvalidOperation {
127 message: format!("Failed to get user selection: {}", e),
128 })?;
129
130 let header_strategy = header_strategy_options[header_strategy_index].to_string();
131
132 println!();
133
134 println!("{}", "⚙️ Generation Preferences".bright_yellow());
136 println!();
137
138 let enable_cache = Confirm::new()
139 .with_prompt("Enable caching for faster regeneration?")
140 .default(true)
141 .interact()
142 .map_err(|e| GenerationError::InvalidOperation {
143 message: format!("Failed to get user input: {}", e),
144 })?;
145
146 println!();
147
148 let enable_backup = Confirm::new()
149 .with_prompt("Enable automatic backups before overwriting files?")
150 .default(false)
151 .interact()
152 .map_err(|e| GenerationError::InvalidOperation {
153 message: format!("Failed to get user input: {}", e),
154 })?;
155
156 println!();
157
158 let conflict_strategy_options = ["ask", "force", "skip"];
159 let conflict_strategy_index = Select::new()
160 .with_prompt("What should happen when a file was modified by you?")
161 .items(&[
162 "ask - Prompt before overwriting (recommended)",
163 "force - Always overwrite without asking",
164 "skip - Skip modified files",
165 ])
166 .default(0)
167 .interact()
168 .map_err(|e| GenerationError::InvalidOperation {
169 message: format!("Failed to get user selection: {}", e),
170 })?;
171
172 let conflict_strategy = conflict_strategy_options[conflict_strategy_index].to_string();
173
174 println!();
175
176 let config = Config {
178 root_dir,
179 schemas: crate::config::model::SchemasConfig {
180 output: schemas_output,
181 naming,
182 },
183 apis: crate::config::model::ApisConfig {
184 output: apis_output,
185 style: api_style,
186 base_url,
187 header_strategy,
188 },
189 generation: crate::config::model::GenerationConfig {
190 enable_cache,
191 enable_backup,
192 conflict_strategy,
193 },
194 ..Config::default()
195 };
196
197 validate_config(&config)?;
198 save_config(&config)?;
199 println!("{}", "✅ Created .vika.json".green());
200 }
201
202 let config = crate::config::loader::load_config()?;
204
205 let root_dir = PathBuf::from(&config.root_dir);
206 ensure_directory(&root_dir)?;
207
208 let schemas_dir = PathBuf::from(&config.schemas.output);
209 ensure_directory(&schemas_dir)?;
210
211 let apis_dir = PathBuf::from(&config.apis.output);
212 ensure_directory(&apis_dir)?;
213
214 let http_client_path = apis_dir.join("http.ts");
216 if !http_client_path.exists() {
217 write_http_client_template(&http_client_path)?;
218 println!(
219 "{}",
220 format!("✅ Created {}", http_client_path.display()).green()
221 );
222 } else {
223 println!(
224 "{}",
225 format!(
226 "⚠️ {} already exists. Skipping.",
227 http_client_path.display()
228 )
229 .yellow()
230 );
231 }
232
233 println!();
234 println!("{}", "✨ Project initialized successfully!".bright_green());
235 println!();
236 println!("Next steps:");
237 println!(" 1. Run: vika-cli generate --spec <path-or-url-to-swagger>");
238 println!(" 2. Select the modules you want to generate");
239
240 Ok(())
241}