mod bound_helper_resolver;
mod context;
use std::collections::{BTreeMap, HashMap, HashSet};
use helm_schema_ast::TemplateExpr;
pub(crate) use context::FragmentEvalContext;
use crate::abstract_value::AbstractValue;
use crate::eval_effect::EvalResult;
use crate::eval_env::EvalEnv;
use crate::expr_eval::eval_expr;
use crate::helper_meta::HelperOutputMeta;
use bound_helper_resolver::{BoundHelperValueResolverParams, eval_expr_result_with_bound_helpers};
pub(crate) fn context_value_from_outer_expr(
expr: &TemplateExpr,
outer_locals: Option<&HashMap<String, AbstractValue>>,
outer_output_meta: Option<&HashMap<String, BTreeMap<String, HelperOutputMeta>>>,
outer: Option<&HashMap<String, AbstractValue>>,
current_dot: Option<&AbstractValue>,
) -> Option<AbstractValue> {
if matches!(expr, TemplateExpr::Variable(var) if var.is_empty()) {
if let Some(binding) = outer_locals.and_then(|locals| locals.get("")) {
return Some(binding.clone());
}
if let Some(bindings) = outer {
return Some(AbstractValue::Dict(
bindings
.iter()
.map(|(key, binding)| (key.clone(), binding.to_context_value()))
.collect(),
));
}
}
let dot = current_dot.cloned().or_else(|| {
outer.map(|bindings| {
AbstractValue::Dict(
bindings
.iter()
.map(|(name, binding)| (name.clone(), binding.clone()))
.collect(),
)
})
});
let env = EvalEnv {
dot,
root_fields: outer.cloned().unwrap_or_default(),
locals: outer_locals.cloned().unwrap_or_default(),
local_output_meta: outer_output_meta.cloned().unwrap_or_default(),
allow_field_root_lookup: true,
..EvalEnv::default()
};
let result = eval_expr(expr, &env);
let mut output_meta = result.effects.local_output_meta.clone();
for path in &result.effects.yaml_serialized_paths {
output_meta.entry(path.clone()).or_default().yaml_serialized = true;
}
result
.value
.map(|value| value.with_output_meta(&output_meta))
.map(|value| value.to_context_value())
}
pub(crate) fn fragment_context_value(
expr: &TemplateExpr,
root_bindings: &HashMap<String, AbstractValue>,
template_bindings: &HashMap<String, AbstractValue>,
template_output_meta: &HashMap<String, BTreeMap<String, HelperOutputMeta>>,
fragment_context: FragmentEvalContext<'_>,
current_dot_fragment: Option<&AbstractValue>,
) -> Option<AbstractValue> {
let locals = locals_with_roots(template_bindings, root_bindings);
context_value_from_outer_expr(
expr,
Some(&locals),
Some(template_output_meta),
Some(root_bindings),
current_dot_fragment,
)
.or_else(|| {
fragment_context.fragment_value_from_expr_with_meta(
expr,
template_bindings,
template_output_meta,
current_dot_fragment,
&mut HashSet::new(),
)
})
}
pub(crate) fn locals_with_roots(
template_bindings: &HashMap<String, AbstractValue>,
root_bindings: &HashMap<String, AbstractValue>,
) -> HashMap<String, AbstractValue> {
let mut locals = template_bindings.clone();
for (key, value) in root_bindings {
locals
.entry(key.clone())
.or_insert_with(|| value.to_context_value());
}
locals
}
pub(crate) fn document_result_from_expr(
expr: &TemplateExpr,
env: &EvalEnv,
outer: Option<&HashMap<String, AbstractValue>>,
current_dot: Option<&AbstractValue>,
context: FragmentEvalContext<'_>,
seen: &mut HashSet<String>,
) -> EvalResult {
eval_expr_result_with_bound_helpers(
expr,
env,
BoundHelperValueResolverParams {
outer,
current_dot,
context,
seen,
},
)
}