diff options
Diffstat (limited to 'gen/gen_commands_file.rs')
| -rw-r--r-- | gen/gen_commands_file.rs | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/gen/gen_commands_file.rs b/gen/gen_commands_file.rs new file mode 100644 index 0000000..a6b7212 --- /dev/null +++ b/gen/gen_commands_file.rs @@ -0,0 +1,188 @@ +use std::path::PathBuf; + +use string_proc::pascal_case; + +use crate::r#gen::constants::{ + COMMAND_LIST, COMMAND_LIST_TEMPLATE, COMMANDS_PATH, REGISTRY_TOML, TEMPLATE_END, TEMPLATE_START, +}; + +/// Generate registry file from Registry.toml configuration +pub async fn generate_commands_file(repo_root: &PathBuf) { + let template_path = repo_root.join(COMMAND_LIST_TEMPLATE); + let output_path = repo_root.join(COMMAND_LIST); + let config_path = repo_root.join(REGISTRY_TOML); + + // Read the template + let template = tokio::fs::read_to_string(&template_path).await.unwrap(); + + // Read and parse the TOML configuration + let config_content = tokio::fs::read_to_string(&config_path).await.unwrap(); + let config: toml::Value = toml::from_str(&config_content).unwrap(); + + // Collect all command configurations + let mut commands = Vec::new(); + let mut nodes = Vec::new(); + + // Collect commands from registry.toml and COMMANDS_PATH in parallel + let (registry_collected, auto_collected) = tokio::join!( + async { + let mut commands = Vec::new(); + let mut nodes = Vec::new(); + + let Some(table) = config.as_table() else { + return (commands, nodes); + }; + + let Some(cmd_table_value) = table.get("cmd") else { + return (commands, nodes); + }; + + let Some(cmd_table) = cmd_table_value.as_table() else { + return (commands, nodes); + }; + + for (key, cmd_value) in cmd_table { + let Some(cmd_config) = cmd_value.as_table() else { + continue; + }; + + let Some(node_value) = cmd_config.get("node") else { + continue; + }; + + let Some(node_str) = node_value.as_str() else { + continue; + }; + + let Some(cmd_type_value) = cmd_config.get("type") else { + continue; + }; + + let Some(cmd_type_str) = cmd_type_value.as_str() else { + continue; + }; + + let n = node_str.replace(".", " "); + nodes.push(n.clone()); + commands.push((key.to_string(), n, cmd_type_str.to_string())); + } + + (commands, nodes) + }, + async { + let mut commands = Vec::new(); + let mut nodes = Vec::new(); + let commands_dir = repo_root.join(COMMANDS_PATH); + if commands_dir.exists() && commands_dir.is_dir() { + let mut entries = tokio::fs::read_dir(&commands_dir).await.unwrap(); + while let Some(entry) = entries.next_entry().await.unwrap() { + let path = entry.path(); + + if !path.is_file() { + continue; + } + + let extension = match path.extension() { + Some(ext) => ext, + None => continue, + }; + + if extension != "rs" { + continue; + } + + let file_name = match path.file_stem().and_then(|s| s.to_str()) { + Some(name) => name, + None => continue, + }; + + // Skip files that start with underscore + if file_name.starts_with('_') { + continue; + } + + // Convert filename to PascalCase + let pascal_name = pascal_case!(file_name); + + let key = file_name.to_string(); + let node = file_name.replace(".", " ").replace("_", " "); + let cmd_type = format!("cmds::cmd::{}::JV{}Command", file_name, pascal_name); + + nodes.push(node.clone()); + commands.push((key, node, cmd_type)); + } + } + (commands, nodes) + } + ); + + // Combine the results + let (mut registry_commands, mut registry_nodes) = registry_collected; + let (mut auto_commands, mut auto_nodes) = auto_collected; + + commands.append(&mut registry_commands); + commands.append(&mut auto_commands); + nodes.append(&mut registry_nodes); + nodes.append(&mut auto_nodes); + + // Extract the node_if template from the template content + const PROCESS_MARKER: &str = "// PROCESS"; + const LINE: &str = "<<LINE>>"; + const NODES: &str = "<<NODES>>"; + + let template_start_index = template + .find(TEMPLATE_START) + .ok_or("Template start marker not found") + .unwrap(); + let template_end_index = template + .find(TEMPLATE_END) + .ok_or("Template end marker not found") + .unwrap(); + + let template_slice = &template[template_start_index..template_end_index + TEMPLATE_END.len()]; + let node_if_template = template_slice + .trim_start_matches(TEMPLATE_START) + .trim_end_matches(TEMPLATE_END) + .trim_matches('\n'); + + // Generate the match arms for each command + let match_arms: String = commands + .iter() + .map(|(key, node, cmd_type)| { + node_if_template + .replace("<<KEY>>", key) + .replace("<<NODE_NAME>>", node) + .replace("<<COMMAND_TYPE>>", cmd_type) + .trim_matches('\n') + .to_string() + }) + .collect::<Vec<_>>() + .join("\n"); + + let nodes_str = format!( + "[\n {}\n ]", + nodes + .iter() + .map(|node| format!("\"{}\".to_string()", node)) + .collect::<Vec<_>>() + .join(", ") + ); + + // Replace the template section with the generated match arms + let final_content = template + .replace(node_if_template, "") + .replace(TEMPLATE_START, "") + .replace(TEMPLATE_END, "") + .replace(PROCESS_MARKER, &match_arms) + .lines() + .filter(|line| !line.trim().is_empty()) + .collect::<Vec<_>>() + .join("\n") + .replace(LINE, "") + .replace(NODES, nodes_str.as_str()); + + // Write the generated code + tokio::fs::write(output_path, final_content).await.unwrap(); + + println!("Generated registry file with {} commands", commands.len()); +} |
