1use serde_json::Value;
7use std::collections::HashMap;
8use std::time::{Duration, Instant};
9use thiserror::Error;
10
11pub struct EnhancedPluginLoader {
13 npm_loader: NPMPluginLoader,
14 native_loader: NativePluginLoader,
15 plugin_registry: PluginRegistry,
16 config_manager: PluginConfigManager,
17 performance_monitor: PluginPerformanceMonitor,
18 cache: PluginCache,
19}
20
21impl EnhancedPluginLoader {
22 pub fn new() -> Self {
24 Self {
25 npm_loader: NPMPluginLoader::new(),
26 native_loader: NativePluginLoader::new(),
27 plugin_registry: PluginRegistry::new(),
28 config_manager: PluginConfigManager::new(),
29 performance_monitor: PluginPerformanceMonitor::new(),
30 cache: PluginCache::new(),
31 }
32 }
33
34 pub fn load_npm_plugin(
36 &mut self,
37 plugin_name: &str,
38 config: &PluginConfig,
39 ) -> Result<PluginInstance, PluginError> {
40 let start_time = Instant::now();
41
42 if let Some(cached) = self
44 .cache
45 .get_plugin(plugin_name, config.version.as_deref())
46 {
47 return Ok(cached.clone());
48 }
49
50 let plugin_info = self
52 .npm_loader
53 .install_plugin(plugin_name, config.version.as_deref())?;
54
55 let instance = PluginInstance {
57 name: plugin_info.name.clone(),
58 version: plugin_info.version.clone(),
59 info: plugin_info,
60 config: config.clone(),
61 execution_mode: config.execution_mode.clone(),
62 security_level: config.security_level.clone(),
63 };
64
65 self.cache
67 .cache_plugin(plugin_name, config.version.as_deref(), &instance);
68
69 let loading_time = start_time.elapsed();
71 self.performance_monitor
72 .record_loading(&instance, loading_time);
73
74 Ok(instance)
75 }
76
77 pub fn load_native_plugin(
79 &mut self,
80 plugin_path: &str,
81 config: &PluginConfig,
82 ) -> Result<PluginInstance, PluginError> {
83 let start_time = Instant::now();
84
85 let plugin_info = self.native_loader.load_plugin(plugin_path)?;
87
88 let instance = PluginInstance {
90 name: plugin_info.name.clone(),
91 version: plugin_info.version.clone(),
92 info: plugin_info,
93 config: config.clone(),
94 execution_mode: ExecutionMode::Native,
95 security_level: config.security_level.clone(),
96 };
97
98 let loading_time = start_time.elapsed();
100 self.performance_monitor
101 .record_loading(&instance, loading_time);
102
103 Ok(instance)
104 }
105
106 pub fn execute_plugin(
108 &mut self,
109 plugin: &PluginInstance,
110 css: &str,
111 ) -> Result<PluginResult, PluginError> {
112 let start_time = Instant::now();
113
114 let result = match plugin.execution_mode {
116 ExecutionMode::Native => self.execute_native_plugin(plugin, css)?,
117 ExecutionMode::NPM => self.execute_npm_plugin(plugin, css)?,
118 ExecutionMode::WebAssembly => self.execute_wasm_plugin(plugin, css)?,
119 ExecutionMode::Sandboxed => self.execute_sandboxed_plugin(plugin, css)?,
120 };
121
122 let execution_time = start_time.elapsed();
124 let metrics = PluginMetrics {
125 execution_time,
126 memory_usage: result.memory_usage,
127 output_size: result.css.len(),
128 success: result.success,
129 total_executions: 1,
130 total_time: execution_time,
131 avg_time: execution_time,
132 max_time: execution_time,
133 min_time: execution_time,
134 loading_time: Duration::from_secs(0),
135 };
136
137 self.performance_monitor
138 .record_execution(plugin, execution_time, metrics);
139
140 Ok(result)
141 }
142
143 pub fn execute_plugin_pipeline(
145 &mut self,
146 plugins: &[PluginInstance],
147 css: &str,
148 ) -> Result<String, PluginError> {
149 let mut processed_css = css.to_string();
150
151 for plugin in plugins {
152 let result = self.execute_plugin(plugin, &processed_css)?;
153 processed_css = result.css;
154 }
155
156 Ok(processed_css)
157 }
158
159 pub fn execute_plugins_parallel(
161 &self,
162 plugins: &[PluginInstance],
163 css: &str,
164 ) -> Result<String, PluginError> {
165 use rayon::prelude::*;
166
167 let chunks: Vec<&[PluginInstance]> = plugins.chunks(4).collect();
169
170 let results: Result<Vec<String>, PluginError> = chunks
171 .par_iter()
172 .map(|chunk| self.execute_plugin_chunk_parallel(chunk, css))
173 .collect();
174
175 let results = results?;
176 Ok(results.join("\n"))
177 }
178
179 fn execute_plugin_chunk(
181 &mut self,
182 plugins: &[PluginInstance],
183 css: &str,
184 ) -> Result<String, PluginError> {
185 let mut processed_css = css.to_string();
186
187 for plugin in plugins {
188 let result = self.execute_plugin(plugin, &processed_css)?;
189 processed_css = result.css;
190 }
191
192 Ok(processed_css)
193 }
194
195 fn execute_plugin_chunk_parallel(
197 &self,
198 plugins: &[PluginInstance],
199 css: &str,
200 ) -> Result<String, PluginError> {
201 let mut processed_css = css.to_string();
202
203 for plugin in plugins {
204 processed_css = format!("/* Processed by {} */\n{}", plugin.name, processed_css);
206 }
207
208 Ok(processed_css)
209 }
210
211 fn execute_native_plugin(
213 &self,
214 _plugin: &PluginInstance,
215 css: &str,
216 ) -> Result<PluginResult, PluginError> {
217 Ok(PluginResult {
219 css: css.to_string(),
220 success: true,
221 memory_usage: 0,
222 warnings: Vec::new(),
223 errors: Vec::new(),
224 })
225 }
226
227 fn execute_npm_plugin(
229 &self,
230 plugin: &PluginInstance,
231 css: &str,
232 ) -> Result<PluginResult, PluginError> {
233 self.npm_loader
234 .execute_plugin(&plugin.info, css, &plugin.config.options)
235 }
236
237 fn execute_wasm_plugin(
239 &self,
240 _plugin: &PluginInstance,
241 css: &str,
242 ) -> Result<PluginResult, PluginError> {
243 Ok(PluginResult {
245 css: css.to_string(),
246 success: true,
247 memory_usage: 0,
248 warnings: Vec::new(),
249 errors: Vec::new(),
250 })
251 }
252
253 fn execute_sandboxed_plugin(
255 &self,
256 plugin: &PluginInstance,
257 css: &str,
258 ) -> Result<PluginResult, PluginError> {
259 let sandbox = PluginSandbox::new(plugin.security_level.clone());
261
262 sandbox.execute_safely(&plugin.info.name, css, &plugin.config.options)
264 }
265
266 pub fn get_statistics(&self) -> PluginStatistics {
268 self.performance_monitor.get_statistics()
269 }
270
271 pub fn discover_plugins(
273 &self,
274 search_paths: &[String],
275 ) -> Result<Vec<PluginInfo>, PluginError> {
276 let mut plugins = Vec::new();
277
278 for path in search_paths {
279 let discovered = self.npm_loader.discover_plugins(path)?;
280 plugins.extend(discovered);
281 }
282
283 Ok(plugins)
284 }
285}
286
287pub struct NPMPluginLoader {
289 npm_client: NPMClient,
290 cache: PluginCache,
291 sandbox: PluginSandbox,
292}
293
294impl NPMPluginLoader {
295 pub fn new() -> Self {
297 Self {
298 npm_client: NPMClient::new(),
299 cache: PluginCache::new(),
300 sandbox: PluginSandbox::new(SecurityLevel::Sandboxed),
301 }
302 }
303
304 pub fn install_plugin(
306 &self,
307 plugin_name: &str,
308 version: Option<&str>,
309 ) -> Result<PluginInfo, PluginError> {
310 if let Some(cached) = self.cache.get_plugin(plugin_name, version) {
312 return Ok(cached.info.clone());
313 }
314
315 let plugin_info = self.npm_client.install(plugin_name, version)?;
317
318 for dependency in &plugin_info.dependencies {
320 self.install_plugin(&dependency.name, Some(&dependency.version))?;
321 }
322
323 self.validate_plugin(&plugin_info)?;
325
326 Ok(plugin_info)
327 }
328
329 pub fn resolve_dependencies(
331 &self,
332 plugin_name: &str,
333 ) -> Result<Vec<PluginDependency>, PluginError> {
334 self.npm_client.get_dependencies(plugin_name)
335 }
336
337 pub fn execute_plugin(
339 &self,
340 plugin_info: &PluginInfo,
341 css: &str,
342 config: &HashMap<String, Value>,
343 ) -> Result<PluginResult, PluginError> {
344 self.sandbox.execute_safely(&plugin_info.name, css, config)
345 }
346
347 pub fn discover_plugins(&self, _path: &str) -> Result<Vec<PluginInfo>, PluginError> {
349 let mut plugins = Vec::new();
350
351 let package_files = self.find_package_files(_path)?;
353
354 for package_file in package_files {
355 let plugin_info = self.parse_package_json(&package_file)?;
356 if self.is_postcss_plugin(&plugin_info) {
357 plugins.push(plugin_info);
358 }
359 }
360
361 Ok(plugins)
362 }
363
364 fn find_package_files(&self, _path: &str) -> Result<Vec<String>, PluginError> {
366 Ok(Vec::new())
368 }
369
370 fn parse_package_json(&self, _file_path: &str) -> Result<PluginInfo, PluginError> {
372 Ok(PluginInfo {
374 name: "example-plugin".to_string(),
375 version: "1.0.0".to_string(),
376 description: "Example plugin".to_string(),
377 author: "Example Author".to_string(),
378 license: "MIT".to_string(),
379 repository: None,
380 dependencies: Vec::new(),
381 postcss_version: "8.0.0".to_string(),
382 node_version: Some("16.0.0".to_string()),
383 rust_version: None,
384 capabilities: vec![PluginCapability::Transform],
385 })
386 }
387
388 fn is_postcss_plugin(&self, plugin_info: &PluginInfo) -> bool {
390 plugin_info
391 .capabilities
392 .contains(&PluginCapability::Transform)
393 || plugin_info.name.contains("postcss")
394 || plugin_info
395 .dependencies
396 .iter()
397 .any(|dep| dep.name == "postcss")
398 }
399
400 fn validate_plugin(&self, plugin_info: &PluginInfo) -> Result<(), PluginError> {
402 if plugin_info.name.is_empty() {
404 return Err(PluginError::PluginNotFound {
405 name: "".to_string(),
406 });
407 }
408
409 if plugin_info.postcss_version != "8.0.0" {
411 return Err(PluginError::CompatibilityError {
412 error: "Incompatible PostCSS version".to_string(),
413 });
414 }
415
416 Ok(())
417 }
418}
419
420pub struct NativePluginLoader;
422
423impl NativePluginLoader {
424 pub fn new() -> Self {
426 Self
427 }
428
429 pub fn load_plugin(&self, plugin_path: &str) -> Result<PluginInfo, PluginError> {
431 Ok(PluginInfo {
433 name: plugin_path.to_string(),
434 version: "1.0.0".to_string(),
435 description: "Native plugin".to_string(),
436 author: "Native Author".to_string(),
437 license: "MIT".to_string(),
438 repository: None,
439 dependencies: Vec::new(),
440 postcss_version: "8.0.0".to_string(),
441 node_version: None,
442 rust_version: Some("1.70.0".to_string()),
443 capabilities: vec![PluginCapability::Transform],
444 })
445 }
446}
447
448pub struct PluginRegistry {
450 plugins: HashMap<String, PluginInfo>,
451 categories: HashMap<String, Vec<String>>,
452 compatibility_matrix: HashMap<String, Vec<String>>,
453}
454
455impl PluginRegistry {
456 pub fn new() -> Self {
458 Self {
459 plugins: HashMap::new(),
460 categories: HashMap::new(),
461 compatibility_matrix: HashMap::new(),
462 }
463 }
464
465 pub fn register_plugin(&mut self, plugin: PluginInfo) -> Result<(), PluginError> {
467 if plugin.name.is_empty() {
469 return Err(PluginError::PluginNotFound {
470 name: "".to_string(),
471 });
472 }
473
474 if self.plugins.contains_key(&plugin.name) {
476 return Err(PluginError::CompatibilityError {
477 error: "Plugin already registered".to_string(),
478 });
479 }
480
481 self.plugins.insert(plugin.name.clone(), plugin);
483
484 Ok(())
485 }
486
487 pub fn find_compatible_plugins(&self, requirements: &PluginRequirements) -> Vec<PluginInfo> {
489 let mut compatible = Vec::new();
490
491 for (_name, plugin) in &self.plugins {
492 if self.is_compatible(plugin, requirements) {
493 compatible.push(plugin.clone());
494 }
495 }
496
497 compatible
498 }
499
500 fn is_compatible(&self, plugin: &PluginInfo, requirements: &PluginRequirements) -> bool {
502 for required_capability in &requirements.capabilities {
504 if !plugin.capabilities.contains(required_capability) {
505 return false;
506 }
507 }
508
509 if plugin.postcss_version != requirements.postcss_version {
511 return false;
512 }
513
514 true
515 }
516
517 pub fn get_plugin_dependencies(&self, plugin_name: &str) -> Result<Vec<String>, PluginError> {
519 if let Some(plugin) = self.plugins.get(plugin_name) {
520 Ok(plugin
521 .dependencies
522 .iter()
523 .map(|dep| dep.name.clone())
524 .collect())
525 } else {
526 Err(PluginError::PluginNotFound {
527 name: plugin_name.to_string(),
528 })
529 }
530 }
531}
532
533pub struct PluginConfigManager {
535 configs: HashMap<String, PluginConfig>,
536 templates: HashMap<String, ConfigTemplate>,
537}
538
539impl PluginConfigManager {
540 pub fn new() -> Self {
542 Self {
543 configs: HashMap::new(),
544 templates: HashMap::new(),
545 }
546 }
547
548 pub fn load_config(
550 &self,
551 plugin_name: &str,
552 _config_path: &str,
553 ) -> Result<PluginConfig, PluginError> {
554 Ok(PluginConfig {
556 name: plugin_name.to_string(),
557 version: None,
558 options: HashMap::new(),
559 dependencies: Vec::new(),
560 execution_mode: ExecutionMode::NPM,
561 security_level: SecurityLevel::Sandboxed,
562 })
563 }
564
565 pub fn generate_template(&self, plugin_name: &str) -> Result<ConfigTemplate, PluginError> {
567 Ok(ConfigTemplate {
569 name: plugin_name.to_string(),
570 template: "{}".to_string(),
571 documentation: "Example configuration".to_string(),
572 })
573 }
574
575 pub fn validate_config(
577 &self,
578 config: &PluginConfig,
579 ) -> Result<Vec<ConfigValidationError>, PluginError> {
580 let mut errors = Vec::new();
581
582 if config.name.is_empty() {
584 errors.push(ConfigValidationError::MissingField("name".to_string()));
585 }
586
587 for dependency in &config.dependencies {
589 if !self.is_dependency_available(&dependency.name) {
590 errors.push(ConfigValidationError::MissingDependency(
591 dependency.name.clone(),
592 ));
593 }
594 }
595
596 Ok(errors)
597 }
598
599 fn is_dependency_available(&self, _dependency_name: &str) -> bool {
601 true
603 }
604}
605
606pub struct PluginPerformanceMonitor {
608 metrics: HashMap<String, PluginMetrics>,
609 alerts: Vec<PerformanceAlert>,
610}
611
612impl PluginPerformanceMonitor {
613 pub fn new() -> Self {
615 Self {
616 metrics: HashMap::new(),
617 alerts: Vec::new(),
618 }
619 }
620
621 pub fn record_execution(
623 &mut self,
624 plugin: &PluginInstance,
625 duration: Duration,
626 metrics: PluginMetrics,
627 ) {
628 let plugin_name = &plugin.name;
629
630 if let Some(existing_metrics) = self.metrics.get_mut(plugin_name) {
631 existing_metrics.total_executions += 1;
632 existing_metrics.total_time += duration;
633 existing_metrics.avg_time =
634 existing_metrics.total_time / existing_metrics.total_executions;
635 existing_metrics.max_time = existing_metrics.max_time.max(duration);
636 existing_metrics.min_time = existing_metrics.min_time.min(duration);
637 } else {
638 self.metrics.insert(plugin_name.clone(), metrics);
639 }
640
641 self.check_performance_alerts(plugin_name, duration);
643 }
644
645 pub fn record_loading(&mut self, plugin: &PluginInstance, duration: Duration) {
647 let plugin_name = &plugin.name;
649
650 if let Some(existing_metrics) = self.metrics.get_mut(plugin_name) {
651 existing_metrics.loading_time = duration;
652 }
653 }
654
655 fn check_performance_alerts(&mut self, plugin_name: &str, duration: Duration) {
657 if duration > Duration::from_millis(1000) {
658 self.alerts.push(PerformanceAlert {
659 plugin: plugin_name.to_string(),
660 issue: "Slow execution".to_string(),
661 duration,
662 timestamp: std::time::SystemTime::now(),
663 });
664 }
665 }
666
667 pub fn get_statistics(&self) -> PluginStatistics {
669 PluginStatistics {
670 total_plugins: self.metrics.len(),
671 total_executions: self.metrics.values().map(|m| m.total_executions).sum(),
672 average_execution_time: self.metrics.values().map(|m| m.avg_time).sum::<Duration>()
673 / self.metrics.len().max(1) as u32,
674 performance_alerts: self.alerts.len(),
675 }
676 }
677}
678
679pub struct PluginSandbox {
681 security_policy: SecurityPolicy,
682 resource_limits: ResourceLimits,
683 allowed_apis: std::collections::HashSet<String>,
684}
685
686impl PluginSandbox {
687 pub fn new(security_level: SecurityLevel) -> Self {
689 Self {
690 security_policy: SecurityPolicy::new(security_level),
691 resource_limits: ResourceLimits::new(),
692 allowed_apis: std::collections::HashSet::new(),
693 }
694 }
695
696 pub fn execute_safely(
698 &self,
699 plugin_name: &str,
700 css: &str,
701 config: &HashMap<String, Value>,
702 ) -> Result<PluginResult, PluginError> {
703 let sandbox_env = self.create_sandbox_environment();
705
706 self.apply_resource_limits(&sandbox_env);
708
709 let result = self.execute_with_constraints(plugin_name, css, config)?;
711
712 self.validate_output(&result.css)?;
714
715 Ok(result)
716 }
717
718 fn create_sandbox_environment(&self) -> SandboxEnvironment {
720 SandboxEnvironment {
721 memory_limit: self.resource_limits.max_memory,
722 execution_time_limit: self.resource_limits.max_execution_time,
723 allowed_apis: self.allowed_apis.clone(),
724 }
725 }
726
727 fn apply_resource_limits(&self, _env: &SandboxEnvironment) {
729 }
731
732 fn execute_with_constraints(
734 &self,
735 _plugin_name: &str,
736 css: &str,
737 _config: &HashMap<String, Value>,
738 ) -> Result<PluginResult, PluginError> {
739 Ok(PluginResult {
741 css: css.to_string(),
742 success: true,
743 memory_usage: 0,
744 warnings: Vec::new(),
745 errors: Vec::new(),
746 })
747 }
748
749 fn validate_output(&self, output: &str) -> Result<(), PluginError> {
751 if output.contains("<script>") || output.contains("javascript:") {
753 return Err(PluginError::SecurityViolation);
754 }
755
756 if output.len() > self.resource_limits.max_output_size {
758 return Err(PluginError::ResourceLimitExceeded);
759 }
760
761 Ok(())
762 }
763}
764
765pub struct PluginCache {
767 plugin_cache: HashMap<String, PluginInstance>,
768 execution_cache: HashMap<String, String>,
769 dependency_cache: HashMap<String, Vec<String>>,
770}
771
772impl PluginCache {
773 pub fn new() -> Self {
775 Self {
776 plugin_cache: HashMap::new(),
777 execution_cache: HashMap::new(),
778 dependency_cache: HashMap::new(),
779 }
780 }
781
782 pub fn cache_plugin(&mut self, name: &str, version: Option<&str>, plugin: &PluginInstance) {
784 let key = format!("{}:{}", name, version.unwrap_or("latest"));
785 self.plugin_cache.insert(key, plugin.clone());
786 }
787
788 pub fn get_plugin(&self, name: &str, version: Option<&str>) -> Option<&PluginInstance> {
790 let key = format!("{}:{}", name, version.unwrap_or("latest"));
791 self.plugin_cache.get(&key)
792 }
793
794 pub fn cache_execution(&mut self, key: &str, result: &str) {
796 self.execution_cache
797 .insert(key.to_string(), result.to_string());
798 }
799
800 pub fn get_cached_execution(&self, key: &str) -> Option<&String> {
802 self.execution_cache.get(key)
803 }
804}
805
806pub struct NPMClient;
808
809impl NPMClient {
810 pub fn new() -> Self {
812 Self
813 }
814
815 pub fn install(
817 &self,
818 package_name: &str,
819 version: Option<&str>,
820 ) -> Result<PluginInfo, PluginError> {
821 Ok(PluginInfo {
823 name: package_name.to_string(),
824 version: version.unwrap_or("latest").to_string(),
825 description: "NPM plugin".to_string(),
826 author: "NPM Author".to_string(),
827 license: "MIT".to_string(),
828 repository: None,
829 dependencies: Vec::new(),
830 postcss_version: "8.0.0".to_string(),
831 node_version: Some("16.0.0".to_string()),
832 rust_version: None,
833 capabilities: vec![PluginCapability::Transform],
834 })
835 }
836
837 pub fn get_dependencies(
839 &self,
840 _package_name: &str,
841 ) -> Result<Vec<PluginDependency>, PluginError> {
842 Ok(Vec::new())
844 }
845}
846
847#[derive(Debug, Clone)]
851pub struct PluginConfig {
852 pub name: String,
853 pub version: Option<String>,
854 pub options: HashMap<String, Value>,
855 pub dependencies: Vec<PluginDependency>,
856 pub execution_mode: ExecutionMode,
857 pub security_level: SecurityLevel,
858}
859
860#[derive(Debug, Clone)]
862pub enum ExecutionMode {
863 Native,
864 NPM,
865 WebAssembly,
866 Sandboxed,
867}
868
869#[derive(Debug, Clone)]
871pub enum SecurityLevel {
872 Trusted,
873 Sandboxed,
874 Restricted,
875}
876
877#[derive(Debug, Clone)]
879pub struct PluginDependency {
880 pub name: String,
881 pub version: String,
882 pub optional: bool,
883}
884
885#[derive(Debug, Clone)]
887pub struct PluginInfo {
888 pub name: String,
889 pub version: String,
890 pub description: String,
891 pub author: String,
892 pub license: String,
893 pub repository: Option<String>,
894 pub dependencies: Vec<PluginDependency>,
895 pub postcss_version: String,
896 pub node_version: Option<String>,
897 pub rust_version: Option<String>,
898 pub capabilities: Vec<PluginCapability>,
899}
900
901#[derive(Debug, Clone, PartialEq)]
903pub enum PluginCapability {
904 Transform,
905 Parse,
906 Stringify,
907 SourceMap,
908 Optimization,
909 Linting,
910 Validation,
911}
912
913#[derive(Debug, Clone)]
915pub struct PluginInstance {
916 pub name: String,
917 pub version: String,
918 pub info: PluginInfo,
919 pub config: PluginConfig,
920 pub execution_mode: ExecutionMode,
921 pub security_level: SecurityLevel,
922}
923
924#[derive(Debug, Clone)]
926pub struct PluginResult {
927 pub css: String,
928 pub success: bool,
929 pub memory_usage: usize,
930 pub warnings: Vec<String>,
931 pub errors: Vec<String>,
932}
933
934#[derive(Debug, Clone)]
936pub struct PluginMetrics {
937 pub execution_time: Duration,
938 pub memory_usage: usize,
939 pub output_size: usize,
940 pub success: bool,
941 pub total_executions: u32,
942 pub total_time: Duration,
943 pub avg_time: Duration,
944 pub max_time: Duration,
945 pub min_time: Duration,
946 pub loading_time: Duration,
947}
948
949impl PluginMetrics {
950 pub fn new() -> Self {
952 Self {
953 execution_time: Duration::from_secs(0),
954 memory_usage: 0,
955 output_size: 0,
956 success: true,
957 total_executions: 0,
958 total_time: Duration::from_secs(0),
959 avg_time: Duration::from_secs(0),
960 max_time: Duration::from_secs(0),
961 min_time: Duration::from_secs(0),
962 loading_time: Duration::from_secs(0),
963 }
964 }
965}
966
967#[derive(Debug, Clone)]
969pub struct PluginRequirements {
970 pub capabilities: Vec<PluginCapability>,
971 pub postcss_version: String,
972 pub node_version: Option<String>,
973 pub rust_version: Option<String>,
974}
975
976#[derive(Debug, Clone)]
978pub struct ConfigTemplate {
979 pub name: String,
980 pub template: String,
981 pub documentation: String,
982}
983
984#[derive(Debug, Clone)]
986pub enum ConfigValidationError {
987 MissingField(String),
988 MissingDependency(String),
989 InvalidValue(String),
990}
991
992#[derive(Debug, Clone)]
994pub struct PerformanceAlert {
995 pub plugin: String,
996 pub issue: String,
997 pub duration: Duration,
998 pub timestamp: std::time::SystemTime,
999}
1000
1001#[derive(Debug, Clone)]
1003pub struct PluginStatistics {
1004 pub total_plugins: usize,
1005 pub total_executions: u32,
1006 pub average_execution_time: Duration,
1007 pub performance_alerts: usize,
1008}
1009
1010#[derive(Debug, Clone)]
1012pub struct SecurityPolicy {
1013 pub level: SecurityLevel,
1014 pub allowed_apis: std::collections::HashSet<String>,
1015 pub resource_limits: ResourceLimits,
1016}
1017
1018impl SecurityPolicy {
1019 pub fn new(level: SecurityLevel) -> Self {
1021 Self {
1022 level,
1023 allowed_apis: std::collections::HashSet::new(),
1024 resource_limits: ResourceLimits::new(),
1025 }
1026 }
1027}
1028
1029#[derive(Debug, Clone)]
1031pub struct ResourceLimits {
1032 pub max_memory: usize,
1033 pub max_execution_time: Duration,
1034 pub max_output_size: usize,
1035}
1036
1037impl ResourceLimits {
1038 pub fn new() -> Self {
1040 Self {
1041 max_memory: 100 * 1024 * 1024, max_execution_time: Duration::from_secs(30),
1043 max_output_size: 10 * 1024 * 1024, }
1045 }
1046}
1047
1048#[derive(Debug, Clone)]
1050pub struct SandboxEnvironment {
1051 pub memory_limit: usize,
1052 pub execution_time_limit: Duration,
1053 pub allowed_apis: std::collections::HashSet<String>,
1054}
1055
1056#[derive(Debug, Error)]
1058pub enum PluginError {
1059 #[error("Plugin not found: {name}")]
1060 PluginNotFound { name: String },
1061
1062 #[error("Plugin installation failed: {error}")]
1063 InstallationFailed { error: String },
1064
1065 #[error("Plugin execution failed: {error}")]
1066 ExecutionFailed { error: String },
1067
1068 #[error("Security violation detected")]
1069 SecurityViolation,
1070
1071 #[error("Resource limit exceeded")]
1072 ResourceLimitExceeded,
1073
1074 #[error("Plugin compatibility error: {error}")]
1075 CompatibilityError { error: String },
1076
1077 #[error("Configuration validation failed: {errors:?}")]
1078 ConfigValidationFailed { errors: Vec<ConfigValidationError> },
1079}
1080
1081#[cfg(test)]
1082mod tests {
1083 use super::*;
1084
1085 #[test]
1086 fn test_enhanced_plugin_loader_creation() {
1087 let loader = EnhancedPluginLoader::new();
1088 assert!(loader.get_statistics().total_plugins == 0);
1089 }
1090
1091 #[test]
1092 fn test_plugin_config_creation() {
1093 let config = PluginConfig {
1094 name: "test-plugin".to_string(),
1095 version: Some("1.0.0".to_string()),
1096 options: HashMap::new(),
1097 dependencies: Vec::new(),
1098 execution_mode: ExecutionMode::NPM,
1099 security_level: SecurityLevel::Sandboxed,
1100 };
1101
1102 assert_eq!(config.name, "test-plugin");
1103 assert_eq!(config.version, Some("1.0.0".to_string()));
1104 }
1105
1106 #[test]
1107 fn test_plugin_metrics_creation() {
1108 let metrics = PluginMetrics::new();
1109 assert_eq!(metrics.total_executions, 0);
1110 assert_eq!(metrics.memory_usage, 0);
1111 }
1112
1113 #[test]
1114 fn test_plugin_registry_operations() {
1115 let mut registry = PluginRegistry::new();
1116
1117 let plugin = PluginInfo {
1118 name: "test-plugin".to_string(),
1119 version: "1.0.0".to_string(),
1120 description: "Test plugin".to_string(),
1121 author: "Test Author".to_string(),
1122 license: "MIT".to_string(),
1123 repository: None,
1124 dependencies: Vec::new(),
1125 postcss_version: "8.0.0".to_string(),
1126 node_version: None,
1127 rust_version: None,
1128 capabilities: vec![PluginCapability::Transform],
1129 };
1130
1131 let result = registry.register_plugin(plugin);
1132 assert!(result.is_ok());
1133 }
1134
1135 #[test]
1136 fn test_plugin_cache_operations() {
1137 let mut cache = PluginCache::new();
1138
1139 let plugin = PluginInstance {
1140 name: "test-plugin".to_string(),
1141 version: "1.0.0".to_string(),
1142 info: PluginInfo {
1143 name: "test-plugin".to_string(),
1144 version: "1.0.0".to_string(),
1145 description: "Test plugin".to_string(),
1146 author: "Test Author".to_string(),
1147 license: "MIT".to_string(),
1148 repository: None,
1149 dependencies: Vec::new(),
1150 postcss_version: "8.0.0".to_string(),
1151 node_version: None,
1152 rust_version: None,
1153 capabilities: vec![PluginCapability::Transform],
1154 },
1155 config: PluginConfig {
1156 name: "test-plugin".to_string(),
1157 version: Some("1.0.0".to_string()),
1158 options: HashMap::new(),
1159 dependencies: Vec::new(),
1160 execution_mode: ExecutionMode::NPM,
1161 security_level: SecurityLevel::Sandboxed,
1162 },
1163 execution_mode: ExecutionMode::NPM,
1164 security_level: SecurityLevel::Sandboxed,
1165 };
1166
1167 cache.cache_plugin("test-plugin", Some("1.0.0"), &plugin);
1168 let cached = cache.get_plugin("test-plugin", Some("1.0.0"));
1169 assert!(cached.is_some());
1170 }
1171}