modcli/loader/
sources.rs

1use crate::command::Command;
2use std::fs;
3use std::path::Path;
4use serde::Deserialize;
5
6pub trait CommandSource {
7    fn load_commands(&self) -> Vec<Box<dyn Command>>;
8}
9
10/// JSON-defined command format
11#[derive(Debug, Deserialize)]
12struct JsonCommand {
13    name: String,
14    #[serde(default)]
15    aliases: Vec<String>,
16    #[serde(default)]
17    help: Option<String>,
18    #[serde(default)]
19    hidden: bool,
20}
21
22/// A command loaded from JSON metadata
23struct DynamicJsonCommand {
24    name: String,
25    #[allow(dead_code)]
26    aliases: Vec<String>,
27    help: Option<String>,
28    hidden: bool,
29}
30
31impl Command for DynamicJsonCommand {
32    fn name(&self) -> &str {
33        &self.name
34    }
35
36    fn aliases(&self) -> &[&str] {
37        &[]
38    }
39
40    fn help(&self) -> Option<&str> {
41        self.help.as_deref()
42    }
43
44    fn hidden(&self) -> bool {
45        self.hidden
46    }
47
48    fn validate(&self, _args: &[String]) -> Result<(), String> {
49        Ok(())
50    }
51
52    fn execute(&self, args: &[String]) {
53        println!("Executed dynamic command '{}': {:?}", self.name, args);
54    }
55}
56
57/// JSON loader from file path
58pub struct JsonFileSource {
59    path: String,
60}
61
62impl JsonFileSource {
63    pub fn new<P: Into<String>>(path: P) -> Self {
64        Self { path: path.into() }
65    }
66}
67
68impl CommandSource for JsonFileSource {
69    fn load_commands(&self) -> Vec<Box<dyn Command>> {
70        let path = Path::new(&self.path);
71        let data = fs::read_to_string(path).expect("Failed to read JSON");
72        let defs: Vec<JsonCommand> = serde_json::from_str(&data).expect("Invalid JSON");
73
74        defs.into_iter()
75            .map(|cmd| {
76                Box::new(DynamicJsonCommand {
77                    name: cmd.name,
78                    aliases: cmd.aliases,
79                    help: cmd.help,
80                    hidden: cmd.hidden,
81                }) as Box<dyn Command>
82            })
83            .collect()
84    }
85}