raz_validation/provider/
leptos.rs

1//! Leptos framework options provider
2
3use crate::error::{ValidationError, ValidationResult};
4use crate::provider::{OptionDef, OptionProvider, OptionValueType, ValueValidator};
5use std::collections::HashMap;
6
7/// Provider for leptos command options
8pub struct LeptosProvider {
9    options: HashMap<String, Vec<OptionDef>>,
10}
11
12impl Default for LeptosProvider {
13    fn default() -> Self {
14        Self::new()
15    }
16}
17
18impl LeptosProvider {
19    pub fn new() -> Self {
20        Self {
21            options: build_leptos_options(),
22        }
23    }
24}
25
26impl OptionProvider for LeptosProvider {
27    fn name(&self) -> &str {
28        "leptos"
29    }
30
31    fn get_options(&self, command: &str) -> Vec<OptionDef> {
32        // Handle leptos subcommands
33        let leptos_command = if let Some(stripped) = command.strip_prefix("leptos ") {
34            stripped // Remove "leptos " prefix
35        } else {
36            command
37        };
38
39        self.options
40            .get(leptos_command)
41            .cloned()
42            .unwrap_or_default()
43    }
44
45    fn validate(&self, command: &str, option: &str, value: Option<&str>) -> ValidationResult<()> {
46        let options = self.get_options(command);
47
48        // Find the option definition
49        let option_def = options
50            .iter()
51            .find(|def| def.name == option)
52            .ok_or_else(|| ValidationError::unknown_option(command, option, vec![]))?;
53
54        // Validate value based on option type
55        match (&option_def.value_type, value) {
56            (OptionValueType::Flag, Some(val)) => Err(ValidationError::UnexpectedValue {
57                option: option.to_string(),
58                value: val.to_string(),
59            }),
60            (OptionValueType::Single(validator), Some(val)) => {
61                validator.validate(val).map_err(|mut e| {
62                    if let ValidationError::InvalidValue {
63                        option: ref mut opt,
64                        ..
65                    } = e
66                    {
67                        *opt = option.to_string();
68                    }
69                    e
70                })
71            }
72            (OptionValueType::Multiple(validator), Some(val)) => {
73                // For multiple values, validate each comma-separated value
74                for v in val.split(',') {
75                    validator.validate(v.trim()).map_err(|mut e| {
76                        if let ValidationError::InvalidValue {
77                            option: ref mut opt,
78                            ..
79                        } = e
80                        {
81                            *opt = option.to_string();
82                        }
83                        e
84                    })?;
85                }
86                Ok(())
87            }
88            (OptionValueType::Single(_) | OptionValueType::Multiple(_), None) => {
89                Err(ValidationError::MissingValue {
90                    option: option.to_string(),
91                })
92            }
93            (OptionValueType::Flag, None) => Ok(()),
94        }
95    }
96
97    fn get_commands(&self) -> Vec<String> {
98        vec![
99            "leptos build".to_string(),
100            "leptos serve".to_string(),
101            "leptos watch".to_string(),
102            "leptos new".to_string(),
103            "leptos end-to-end".to_string(),
104        ]
105    }
106
107    fn supports_command(&self, command: &str) -> bool {
108        command.starts_with("leptos ") || self.get_commands().contains(&command.to_string())
109    }
110}
111
112/// Build the leptos options catalog
113fn build_leptos_options() -> HashMap<String, Vec<OptionDef>> {
114    let mut options = HashMap::new();
115
116    // Leptos build command options
117    options.insert(
118        "build".to_string(),
119        vec![
120            OptionDef::flag("--release", "Build in release mode"),
121            OptionDef::multiple(
122                "--bin-features",
123                "Features to enable for binary compilation",
124                ValueValidator::Any,
125            ),
126            OptionDef::multiple(
127                "--lib-features",
128                "Features to enable for library compilation",
129                ValueValidator::Any,
130            ),
131            OptionDef::flag("--precompress", "Pre-compress static assets"),
132            OptionDef::single(
133                "--bin-target-dir",
134                "Directory for binary artifacts",
135                ValueValidator::DirectoryPath,
136            ),
137            OptionDef::single(
138                "--lib-target-dir",
139                "Directory for library artifacts",
140                ValueValidator::DirectoryPath,
141            ),
142            OptionDef::single(
143                "--site-root",
144                "Root directory for the site",
145                ValueValidator::DirectoryPath,
146            ),
147            OptionDef::single(
148                "--site-pkg-dir",
149                "Directory for site packages",
150                ValueValidator::DirectoryPath,
151            ),
152            OptionDef::single(
153                "--site-addr",
154                "Address to serve the site",
155                ValueValidator::Any,
156            ),
157            OptionDef::single(
158                "--reload-port",
159                "Port for reload server",
160                ValueValidator::Number,
161            ),
162            OptionDef::flag("--hot-reload", "Enable hot reloading"),
163            OptionDef::flag("--no-default-features", "Disable default features"),
164        ],
165    );
166
167    // Leptos serve command options
168    options.insert(
169        "serve".to_string(),
170        vec![
171            OptionDef::flag("--release", "Serve release build"),
172            OptionDef::single("--port", "Port to serve on", ValueValidator::Number),
173            OptionDef::single("--host", "Host to serve on", ValueValidator::Any),
174            OptionDef::flag("--hot-reload", "Enable hot reloading"),
175            OptionDef::single(
176                "--reload-port",
177                "Port for reload server",
178                ValueValidator::Number,
179            ),
180            OptionDef::single(
181                "--site-root",
182                "Root directory for the site",
183                ValueValidator::DirectoryPath,
184            ),
185            OptionDef::single(
186                "--site-pkg-dir",
187                "Directory for site packages",
188                ValueValidator::DirectoryPath,
189            ),
190            OptionDef::multiple(
191                "--bin-features",
192                "Features to enable for binary compilation",
193                ValueValidator::Any,
194            ),
195            OptionDef::multiple(
196                "--lib-features",
197                "Features to enable for library compilation",
198                ValueValidator::Any,
199            ),
200        ],
201    );
202
203    // Leptos watch command options
204    options.insert(
205        "watch".to_string(),
206        vec![
207            OptionDef::flag("--release", "Watch release build"),
208            OptionDef::flag("--hot-reload", "Enable hot reloading"),
209            OptionDef::single(
210                "--reload-port",
211                "Port for reload server",
212                ValueValidator::Number,
213            ),
214            OptionDef::single(
215                "--site-root",
216                "Root directory for the site",
217                ValueValidator::DirectoryPath,
218            ),
219            OptionDef::multiple(
220                "--bin-features",
221                "Features to enable for binary compilation",
222                ValueValidator::Any,
223            ),
224            OptionDef::multiple(
225                "--lib-features",
226                "Features to enable for library compilation",
227                ValueValidator::Any,
228            ),
229            OptionDef::flag("--no-default-features", "Disable default features"),
230        ],
231    );
232
233    // Leptos new command options
234    options.insert(
235        "new".to_string(),
236        vec![
237            OptionDef::single("--name", "Name of the new project", ValueValidator::Any),
238            OptionDef::single(
239                "--template",
240                "Template to use",
241                ValueValidator::Enum(vec![
242                    "start".to_string(),
243                    "start-axum".to_string(),
244                    "start-actix".to_string(),
245                    "csr".to_string(),
246                    "ssr".to_string(),
247                ]),
248            ),
249            OptionDef::flag("--git", "Initialize git repository"),
250            OptionDef::flag("--no-git", "Don't initialize git repository"),
251        ],
252    );
253
254    // Leptos end-to-end command options
255    options.insert(
256        "end-to-end".to_string(),
257        vec![
258            OptionDef::flag("--release", "Run end-to-end tests in release mode"),
259            OptionDef::single("--port", "Port for test server", ValueValidator::Number),
260            OptionDef::multiple(
261                "--bin-features",
262                "Features to enable for binary compilation",
263                ValueValidator::Any,
264            ),
265            OptionDef::multiple(
266                "--lib-features",
267                "Features to enable for library compilation",
268                ValueValidator::Any,
269            ),
270        ],
271    );
272
273    options
274}