helm_schema_ir/contract/
finalized.rs1use std::collections::{BTreeMap, BTreeSet};
2
3use super::{ContractDocument, ContractUse};
4use crate::contract_signal_builder::derive_schema_signals_from_contract_parts;
5use crate::observed_facts::ObservedFacts;
6use helm_schema_core::{ConditionalGuard, ContractSchemaSignals, GuardedValuesDefaultSource};
7
8fn activation_guards(guards: &[crate::Guard]) -> Option<Vec<ConditionalGuard>> {
9 let mut lowered = guards
10 .iter()
11 .map(ConditionalGuard::try_from)
12 .collect::<Result<Vec<_>, _>>()
13 .ok()?;
14 lowered.sort();
15 lowered.dedup();
16 Some(lowered)
17}
18
19fn activation_guard_disjunction(guard_sets: Vec<Vec<ConditionalGuard>>) -> Vec<ConditionalGuard> {
20 let mut guard_sets =
21 helm_schema_core::GuardDnf::normalize_conditional_guard_disjunction(guard_sets);
22 match guard_sets.as_mut_slice() {
23 [] => Vec::new(),
24 [guards] => std::mem::take(guards),
25 _ => vec![ConditionalGuard::AnyOf(
26 guard_sets
27 .into_iter()
28 .map(|mut guards| match guards.len() {
29 1 => guards.remove(0),
30 _ => ConditionalGuard::AllOf(guards),
31 })
32 .collect(),
33 )],
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct FinalizedContract {
44 uses: Vec<ContractUse>,
45 schema_signals: ContractSchemaSignals,
46}
47
48impl FinalizedContract {
49 pub(in crate::contract) fn new(
50 normalized_uses: Vec<ContractUse>,
51 observed_facts: &ObservedFacts,
52 values_program_wrappers: BTreeSet<helm_schema_core::ValuesProgramWrapper>,
53 values_program_wrapper_exclusions: BTreeSet<helm_schema_core::ValuesPath>,
54 dependency_values_root_fragments: &BTreeSet<String>,
55 ) -> Self {
56 let mut default_guard_sets = BTreeMap::<_, Vec<Vec<ConditionalGuard>>>::new();
57 for fact in &observed_facts.activated_values_default_sources {
58 if let Some(guards) = activation_guards(&fact.guards) {
59 default_guard_sets
60 .entry(fact.source.clone())
61 .or_default()
62 .push(guards);
63 }
64 }
65 let guarded_values_default_sources = default_guard_sets
66 .into_iter()
67 .map(|(source, guard_sets)| GuardedValuesDefaultSource {
68 outer_guards: activation_guard_disjunction(guard_sets),
69 source,
70 })
71 .collect::<Vec<_>>();
72 let mut overlay_guard_sets = BTreeMap::<_, Vec<Vec<ConditionalGuard>>>::new();
73 for fact in &observed_facts.activated_values_root_overlays {
74 if let Some(guards) = activation_guards(&fact.guards) {
75 overlay_guard_sets
76 .entry((fact.target_path.clone(), fact.source_path.clone()))
77 .or_default()
78 .push(guards);
79 }
80 }
81 let guarded_root_overlays = overlay_guard_sets
82 .into_iter()
83 .map(|((target_path, source_path), guard_sets)| {
84 (
85 activation_guard_disjunction(guard_sets),
86 target_path,
87 source_path,
88 )
89 })
90 .chain(observed_facts.values_root_overlays.iter().map(|fact| {
91 (
92 Vec::new(),
93 fact.target_path.clone(),
94 fact.source_path.clone(),
95 )
96 }))
97 .collect::<Vec<_>>();
98 let schema_signals = derive_schema_signals_from_contract_parts(
99 &normalized_uses,
100 observed_facts,
101 dependency_values_root_fragments,
102 )
103 .with_values_default_sources(observed_facts.values_default_sources.clone())
104 .with_guarded_values_default_sources(guarded_values_default_sources)
105 .with_scoped_guarded_root_overlay_requirement_implications(guarded_root_overlays)
106 .with_values_program_wrappers(values_program_wrappers)
107 .with_values_program_wrapper_exclusions(values_program_wrapper_exclusions);
108
109 Self {
110 uses: normalized_uses,
111 schema_signals,
112 }
113 }
114
115 #[must_use]
117 pub fn uses(&self) -> &[ContractUse] {
118 &self.uses
119 }
120
121 #[must_use]
123 pub fn schema_signals(&self) -> &ContractSchemaSignals {
124 &self.schema_signals
125 }
126
127 #[must_use]
129 pub fn document(&self) -> ContractDocument {
130 ContractDocument::from_contract_uses(self.uses.clone())
131 }
132
133 #[must_use]
135 pub fn into_schema_signals(self) -> ContractSchemaSignals {
136 self.schema_signals
137 }
138}