extern crate fs_extra;
use std::{
collections::BTreeMap,
fs::{self, File},
io::{BufReader, Read},
path::Path,
};
use clap::Parser;
use fs_extra::dir::create;
use include_dir::{Dir, include_dir};
use regex::Regex;
use serde::{Deserialize, Serialize};
static TEMPLATE_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/template");
#[derive(Debug, Serialize, Deserialize)]
struct PackageJson {
name: String,
#[serde(flatten)]
other: serde_json::Value,
}
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Cli {
#[arg(long)]
plugin_name: String,
#[arg(long, default_value_t = 8080)]
port: u16,
}
fn main() {
let args = Cli::parse();
let plugin_name = args.plugin_name;
let plugin_port = args.port;
let plugin_path = Path::new("plugins").join(&plugin_name);
create(plugin_path.clone(), true).expect("Failed to create a folder");
TEMPLATE_DIR
.extract(plugin_path.clone())
.expect("Failed to extract the template folder!");
update_package_json_name_field(plugin_name.clone());
add_port_entry(plugin_name.clone(), plugin_port);
write_plugin_name_to_env(plugin_name.clone());
}
fn write_plugin_name_to_env(plugin_name: String) {
let env_file_path = Path::new("plugins").join(&plugin_name).join(".env");
let env_file = File::open(&env_file_path).expect("Failed to open .env file!");
let mut reader = BufReader::new(&env_file);
let mut env_variables = String::new();
reader
.read_to_string(&mut env_variables)
.expect("Failed to read the contents of the .env file!");
env_variables.push_str(format!("VUE_APP_NAME={}", plugin_name).as_str());
}
fn update_package_json_name_field(plugin_name: String) {
let plugin_path = Path::new("plugins").join(&plugin_name);
let package_json_path = plugin_path.join("package.json");
let file = File::open(&package_json_path).expect("Failed to open file");
let reader = BufReader::new(file);
let mut package_json: PackageJson = serde_json::from_reader(reader).expect("Failed");
package_json.name = plugin_name;
let updated = serde_json::to_string_pretty(&package_json).expect("Failed to update");
fs::write(package_json_path, updated).expect("Failed to write updated content");
}
fn add_port_entry(plugin_name: String, plugin_port: u16) {
let ports_file_path = Path::new("scripts/ports.js");
let content =
fs::read_to_string(&ports_file_path).expect("Failed to look for scripts/ports.js file");
let regex =
Regex::new(r#"module\.exports\s*=\s*\{([\s\S]*?)\};?"#).expect("Failed to create a regex");
let parsed_content = regex.captures(&content).expect("Failed to parse ports.js");
let object_body = parsed_content.get(1).unwrap().as_str();
let mut map = BTreeMap::new();
for line in object_body.lines() {
let line = line.trim().trim_end_matches(",");
if line.is_empty() {
continue;
}
if let Some((key, value)) = line.split_once(":") {
let key = key.trim().to_string();
let value = value.trim().to_string();
map.insert(key, value);
}
}
map.insert(plugin_name.clone(), plugin_port.to_string());
let mut new_object = String::from("module.exports = {\n");
for (key, value) in &map {
new_object.push_str(&format!(" {}: {},\n", key, value));
}
new_object.push_str("};\n");
fs::write(ports_file_path, new_object).expect("Failed to write new content to ports.js");
println!(
"✅ Added {}: {} to ports.js",
plugin_name.clone(),
plugin_port
);
}