use {
crate::{error::CliResult, IdlCommand},
quasar_idl::{codegen, parser},
std::path::{Path, PathBuf},
};
pub fn generate(crate_path: &Path, generate_typescript: bool) -> CliResult {
let parsed = parser::parse_program(crate_path);
let client_code = codegen::rust::generate_client(&parsed);
let client_cargo_toml = codegen::rust::generate_cargo_toml(&parsed.crate_name, &parsed.version);
let idl = parser::build_idl(parsed);
let idl_dir = PathBuf::from("target").join("idl");
std::fs::create_dir_all(&idl_dir)?;
let idl_path = idl_dir.join(format!("{}.idl.json", idl.metadata.name));
let json = serde_json::to_string_pretty(&idl)
.map_err(|e| anyhow::anyhow!("failed to serialize IDL: {e}"))?;
std::fs::write(&idl_path, &json)?;
if generate_typescript {
let ts_code = codegen::typescript::generate_ts_client(&idl);
let ts_kit_code = codegen::typescript::generate_ts_client_kit(&idl);
let ts_dir = PathBuf::from("target")
.join("client")
.join("typescript")
.join(&idl.metadata.name);
std::fs::create_dir_all(&ts_dir)?;
std::fs::write(ts_dir.join("web3.ts"), &ts_code)?;
std::fs::write(ts_dir.join("kit.ts"), &ts_kit_code)?;
let needs_codecs =
!idl.types.is_empty() || idl.instructions.iter().any(|ix| !ix.args.is_empty());
let codecs_dep = if needs_codecs {
"\n \"@solana/codecs\": \"^6.2.0\","
} else {
""
};
let ts_package_json = format!(
r#"{{
"name": "{crate_name}-client",
"version": "{version}",
"private": true,
"exports": {{
"./web3.js": "./web3.ts",
"./kit": "./kit.ts"
}},
"dependencies": {{{codecs_dep}
"@solana/kit": "^6.0.0",
"@solana/web3.js": "github:blueshift-gg/web3.js#v2"
}}
}}
"#,
crate_name = idl.metadata.crate_name,
version = idl.metadata.version,
);
std::fs::write(ts_dir.join("package.json"), &ts_package_json)?;
}
let crate_name = &idl.metadata.crate_name;
let client_dir = PathBuf::from("target")
.join("client")
.join("rust")
.join(format!("{}-client", crate_name));
let client_src_dir = client_dir.join("src");
std::fs::create_dir_all(&client_src_dir)?;
std::fs::write(client_dir.join("Cargo.toml"), &client_cargo_toml)?;
std::fs::write(client_src_dir.join("lib.rs"), &client_code)?;
Ok(())
}
pub fn run(command: IdlCommand) -> CliResult {
let crate_path = &command.crate_path;
if !crate_path.exists() {
eprintln!("Error: path does not exist: {}", crate_path.display());
std::process::exit(1);
}
generate(crate_path, true)?;
println!(" {}", crate::style::success("IDL generated"));
Ok(())
}