forge/cmd/generate/
mod.rs

1use clap::{Parser, Subcommand};
2use eyre::Result;
3use foundry_common::fs;
4use std::path::Path;
5use yansi::Paint;
6
7/// CLI arguments for `forge generate`.
8#[derive(Debug, Parser)]
9pub struct GenerateArgs {
10    #[command(subcommand)]
11    pub sub: GenerateSubcommands,
12}
13
14#[derive(Debug, Subcommand)]
15pub enum GenerateSubcommands {
16    /// Scaffolds test file for given contract.
17    Test(GenerateTestArgs),
18}
19
20#[derive(Debug, Parser)]
21pub struct GenerateTestArgs {
22    /// Contract name for test generation.
23    #[arg(long, short, value_name = "CONTRACT_NAME")]
24    pub contract_name: String,
25}
26
27impl GenerateTestArgs {
28    pub fn run(self) -> Result<()> {
29        sh_warn!("`forge generate` is deprecated and will be removed in a future version")?;
30
31        let contract_name = format_identifier(&self.contract_name, true);
32        let instance_name = format_identifier(&self.contract_name, false);
33
34        // Create the test file content.
35        let test_content = include_str!("../../../assets/generated/TestTemplate.t.sol");
36        let test_content = test_content
37            .replace("{contract_name}", &contract_name)
38            .replace("{instance_name}", &instance_name);
39
40        // Create the test directory if it doesn't exist.
41        fs::create_dir_all("test")?;
42
43        // Define the test file path
44        let test_file_path = Path::new("test").join(format!("{contract_name}.t.sol"));
45
46        // Write the test content to the test file.
47        fs::write(&test_file_path, test_content)?;
48
49        sh_println!("{} test file: {}", "Generated".green(), test_file_path.to_str().unwrap())?;
50        Ok(())
51    }
52}
53
54/// Utility function to convert an identifier to pascal or camel case.
55fn format_identifier(input: &str, is_pascal_case: bool) -> String {
56    let mut result = String::new();
57    let mut capitalize_next = is_pascal_case;
58
59    for word in input.split_whitespace() {
60        if !word.is_empty() {
61            let (first, rest) = word.split_at(1);
62            let formatted_word = if capitalize_next {
63                format!("{}{}", first.to_uppercase(), rest)
64            } else {
65                format!("{}{}", first.to_lowercase(), rest)
66            };
67            capitalize_next = true;
68            result.push_str(&formatted_word);
69        }
70    }
71    result
72}