omena_semantic/
selector_identity.rs1use std::collections::BTreeSet;
8
9use serde::Serialize;
10
11use crate::StyleSelectorIdentityFactsV0;
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
14#[serde(rename_all = "camelCase")]
15pub struct SelectorIdentityEngineSummaryV0 {
16 pub schema_version: &'static str,
17 pub product: &'static str,
18 pub canonical_id_count: usize,
19 pub canonical_ids: Vec<SelectorCanonicalIdentityV0>,
20 pub rewrite_safety: SelectorIdentityRewriteSafetyV0,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
24#[serde(rename_all = "camelCase")]
25pub struct SelectorCanonicalIdentityV0 {
26 pub canonical_id: String,
27 pub local_name: String,
28 pub identity_kind: &'static str,
29 pub rewrite_safety: &'static str,
30 pub blockers: Vec<&'static str>,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
34#[serde(rename_all = "camelCase")]
35pub struct SelectorIdentityRewriteSafetyV0 {
36 pub all_canonical_ids_rewrite_safe: bool,
37 pub safe_canonical_ids: Vec<String>,
38 pub blocked_canonical_ids: Vec<String>,
39 pub blockers: Vec<&'static str>,
40}
41
42pub fn summarize_selector_identity_engine(
43 facts: &StyleSelectorIdentityFactsV0,
44) -> SelectorIdentityEngineSummaryV0 {
45 let bem_safe = facts
46 .bem_suffix_safe_names
47 .iter()
48 .cloned()
49 .collect::<BTreeSet<_>>();
50 let nested_unsafe = facts
51 .nested_unsafe_names
52 .iter()
53 .cloned()
54 .collect::<BTreeSet<_>>();
55
56 let canonical_ids = facts
57 .canonical_names
58 .iter()
59 .map(|name| {
60 let blockers = if nested_unsafe.contains(name) {
61 vec!["nested-expansion"]
62 } else {
63 Vec::new()
64 };
65 SelectorCanonicalIdentityV0 {
66 canonical_id: format!("selector:{name}"),
67 local_name: name.clone(),
68 identity_kind: if bem_safe.contains(name) {
69 "bemSuffix"
70 } else {
71 "localClass"
72 },
73 rewrite_safety: if blockers.is_empty() {
74 "safe"
75 } else {
76 "blocked"
77 },
78 blockers,
79 }
80 })
81 .collect::<Vec<_>>();
82
83 let safe_canonical_ids = canonical_ids
84 .iter()
85 .filter(|identity| identity.blockers.is_empty())
86 .map(|identity| identity.canonical_id.clone())
87 .collect::<Vec<_>>();
88 let blocked_canonical_ids = canonical_ids
89 .iter()
90 .filter(|identity| !identity.blockers.is_empty())
91 .map(|identity| identity.canonical_id.clone())
92 .collect::<Vec<_>>();
93
94 SelectorIdentityEngineSummaryV0 {
95 schema_version: "0",
96 product: "omena-semantic.selector-identity",
97 canonical_id_count: canonical_ids.len(),
98 canonical_ids,
99 rewrite_safety: SelectorIdentityRewriteSafetyV0 {
100 all_canonical_ids_rewrite_safe: blocked_canonical_ids.is_empty(),
101 safe_canonical_ids,
102 blocked_canonical_ids,
103 blockers: if nested_unsafe.is_empty() {
104 Vec::new()
105 } else {
106 vec!["nested-expansion"]
107 },
108 },
109 }
110}