vercel_rpc_cli/
commands.rs1use std::fs;
2use std::path::Path;
3
4use anyhow::{Context, Result};
5
6use crate::config::RpcConfig;
7use crate::{codegen, parser};
8
9pub fn cmd_scan(config: &RpcConfig) -> Result<()> {
12 let manifest = parser::scan_directory(&config.input)?;
13
14 println!(
15 "Discovered {} procedure(s), {} struct(s), {} enum(s):\n",
16 manifest.procedures.len(),
17 manifest.structs.len(),
18 manifest.enums.len(),
19 );
20
21 for proc in &manifest.procedures {
22 let input_str = proc
23 .input
24 .as_ref()
25 .map(|t| t.to_string())
26 .unwrap_or_else(|| "()".to_string());
27 let output_str = proc
28 .output
29 .as_ref()
30 .map(|t| t.to_string())
31 .unwrap_or_else(|| "()".to_string());
32
33 println!(
34 " {:?} {} ({}) -> {} [{}]",
35 proc.kind,
36 proc.name,
37 input_str,
38 output_str,
39 proc.source_file.display(),
40 );
41 }
42
43 for s in &manifest.structs {
44 println!("\n struct {} {{", s.name);
45 for field in &s.fields {
46 println!(" {}: {},", field.name, field.ty);
47 }
48 println!(" }}");
49 }
50
51 for e in &manifest.enums {
52 let variants: Vec<&str> = e.variants.iter().map(|v| v.name.as_str()).collect();
53 println!("\n enum {} {{ {} }}", e.name, variants.join(", "));
54 }
55
56 println!("\n--- JSON manifest ---");
58 println!("{}", serde_json::to_string_pretty(&manifest)?);
59
60 Ok(())
61}
62
63pub fn cmd_generate(config: &RpcConfig) -> Result<()> {
66 let manifest = parser::scan_directory(&config.input)?;
67
68 let types_content = codegen::typescript::generate_types_file(
70 &manifest,
71 config.codegen.preserve_docs,
72 config.codegen.naming.fields,
73 );
74 write_file(&config.output.types, &types_content)?;
75 println!(
76 "Generated {} ({} procedure(s), {} struct(s), {} enum(s)) -> {}",
77 config.output.types.display(),
78 manifest.procedures.len(),
79 manifest.structs.len(),
80 manifest.enums.len(),
81 bytecount(&types_content),
82 );
83
84 let client_content = codegen::client::generate_client_file(
86 &manifest,
87 &config.output.imports.types_specifier(),
88 config.codegen.preserve_docs,
89 );
90 write_file(&config.output.client, &client_content)?;
91 println!(
92 "Generated {} -> {}",
93 config.output.client.display(),
94 bytecount(&client_content),
95 );
96
97 Ok(())
98}
99
100pub fn write_file(path: &Path, content: &str) -> Result<()> {
102 if let Some(parent) = path.parent() {
103 fs::create_dir_all(parent)
104 .with_context(|| format!("Failed to create directory {}", parent.display()))?;
105 }
106 fs::write(path, content).with_context(|| format!("Failed to write {}", path.display()))?;
107 Ok(())
108}
109
110pub fn bytecount(s: &str) -> String {
112 let bytes = s.len();
113 if bytes < 1024 {
114 format!("{bytes} bytes")
115 } else {
116 format!("{:.1} KB", bytes as f64 / 1024.0)
117 }
118}