extern crate fs_extra;
use std::{
collections::BTreeMap,
fs::{self, File},
io::{BufRead, BufReader, Write},
path::Path,
};
use clap::Parser;
use create_platon_plugin::{convert_to_camel_case, convert_to_kebab_case};
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_to_ports_file(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 mut env_file = File::options()
.append(true)
.write(true)
.open(&env_file_path)
.expect("Failed to open .env file!");
writeln!(env_file, "\nVUE_APP_NAME={}", plugin_name.clone())
.expect("Failed to write the plugin's name to .env file!");
println!(
"✅ Added VUE_APP_NAME={} to the .env file!",
plugin_name.clone()
);
}
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 = convert_to_kebab_case(&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");
println!("✅ Updated package.json")
}
fn add_port_entry_to_webpack_dev_server(plugin_name: String, plugin_port: u16) {
let webpack_config_path = Path::new("plugins")
.join(plugin_name.clone())
.join("webpack.config.js");
let mut webpack_config = File::options()
.write(true)
.open(webpack_config_path)
.expect("Failed to open webpack.config.js!");
let reader = BufReader::new(&webpack_config);
for line in reader.lines() {
let line = line.expect("Failed to read the line!");
if line.is_empty() {
continue;
}
if let Some((key, mut value)) = line.split_once(":") {
if key != "port" {
continue;
};
value = &plugin_port.to_string();
}
}
}
fn add_port_entry_to_ports_file(plugin_name: String, plugin_port: u16) {
let plugin_name = convert_to_camel_case(&plugin_name);
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
);
}