light_fw_cli_core/
resolve.rs1use std::collections::BTreeSet;
2
3use crate::registry::ComponentRegistry;
4use crate::scan::ScanResult;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct RequiredComponent {
9 pub name: String,
11}
12
13pub fn needed_components(
18 scan: &ScanResult,
19 registry: &ComponentRegistry,
20) -> Vec<RequiredComponent> {
21 let mut names: BTreeSet<String> = BTreeSet::new();
22 for tag in scan.tags.keys() {
23 if let Some(component) = registry.component_for_element(tag) {
24 names.insert(component.name.clone());
25 }
26 }
27 for attr in scan.attributes.keys() {
28 if let Some(component) = registry.component_for_attribute(attr) {
29 names.insert(component.name.clone());
30 continue;
31 }
32 if is_directive(attr)
33 && let Some(component) = registry.component_for_directive(attr)
34 {
35 names.insert(component.name.clone());
36 }
37 }
38 names
39 .into_iter()
40 .map(|name| RequiredComponent { name })
41 .collect()
42}
43
44fn is_directive(attr: &str) -> bool {
46 attr.starts_with('@') || attr.starts_with(':') || attr.starts_with("v-")
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use crate::scan::ScanResult;
53
54 fn scan_with(tags: &[&str], attrs: &[&str]) -> ScanResult {
55 let mut scan = ScanResult::default();
56 for t in tags {
57 scan.tags.insert((*t).to_string(), 1);
58 }
59 for a in attrs {
60 scan.attributes.insert((*a).to_string(), 1);
61 }
62 scan
63 }
64
65 #[test]
66 fn resolves_needed_components_from_tags() {
67 let registry = ComponentRegistry::builtin();
68 let scan = scan_with(&["text", "checkbox", "div"], &[]);
69 let needed = needed_components(&scan, ®istry);
70 let names: Vec<_> = needed.iter().map(|c| c.name.as_str()).collect();
71 assert_eq!(
72 names,
73 vec!["light-fw-element-form"],
74 "text и div входят в ядро и не сопоставляются с компонентами"
75 );
76 }
77
78 #[test]
79 fn resolves_directives_and_attributes() {
80 let registry = ComponentRegistry::builtin();
81 let scan = scan_with(&[], &["required", "@validate"]);
82 let needed = needed_components(&scan, ®istry);
83 assert_eq!(needed.len(), 1);
84 assert_eq!(needed[0].name, "light-fw-behavior-validation");
85 }
86
87 #[test]
88 fn no_duplicates_for_shared_component() {
89 let registry = ComponentRegistry::builtin();
90 let scan = scan_with(&["checkbox", "radio"], &["required"]);
91 let needed = needed_components(&scan, ®istry);
92 assert_eq!(needed.len(), 2, "form + validation, без дублей");
93 }
94}