helm_schema_syntax/
literal.rs1use serde_json::{Map, Value};
2
3use crate::{
4 BlockScalar, MappingEntry, Node, ScalarPart, ScalarParts, SequenceItem, TemplatedDocument,
5};
6
7impl TemplatedDocument<'_> {
8 #[must_use]
10 pub fn literal_mapping_value(&self, entry: &MappingEntry) -> Option<Value> {
11 if let Some(value) = &entry.value {
12 return self.literal_scalar(value);
13 }
14 if let Some(block) = &entry.block {
15 return self.literal_block(block);
16 }
17 if entry.children.is_empty() {
18 return Some(Value::Null);
19 }
20 self.literal_nodes(&entry.children)
21 }
22
23 #[must_use]
25 pub fn literal_sequence_value(&self, item: &SequenceItem) -> Option<Value> {
26 if let Some(value) = &item.value {
27 return self.literal_scalar(value);
28 }
29 if let Some(block) = &item.block {
30 return self.literal_block(block);
31 }
32 if item.children.is_empty() {
33 return Some(Value::Null);
34 }
35 self.literal_nodes(&item.children)
36 }
37
38 #[must_use]
40 pub fn literal_scalar(&self, scalar: &ScalarParts) -> Option<Value> {
41 if scalar
42 .parts
43 .iter()
44 .any(|part| matches!(part, ScalarPart::Hole(_)))
45 {
46 return None;
47 }
48 self.literal_source(scalar.span.start, scalar.span.end)
49 }
50
51 fn literal_nodes(&self, nodes: &[Node]) -> Option<Value> {
52 let mut mapping = Map::new();
53 let mut sequence = Vec::new();
54 let mut shape = None;
55
56 for node in nodes {
57 match node {
58 Node::Mapping(entry) => {
59 if shape == Some(false) {
60 return None;
61 }
62 shape = Some(true);
63 let key = self.literal_scalar(&entry.key)?;
64 mapping.insert(
65 key.as_str()?.to_string(),
66 self.literal_mapping_value(entry)?,
67 );
68 }
69 Node::Sequence(item) => {
70 if shape == Some(true) {
71 return None;
72 }
73 shape = Some(false);
74 sequence.push(self.literal_sequence_value(item)?);
75 }
76 Node::Comment(_) | Node::Control(_) | Node::Output(_) | Node::Opaque(_) => {}
77 Node::Scalar(_) => return None,
78 }
79 }
80
81 match shape {
82 Some(true) => Some(Value::Object(mapping)),
83 Some(false) => Some(Value::Array(sequence)),
84 None => Some(Value::Null),
85 }
86 }
87
88 fn literal_block(&self, block: &BlockScalar) -> Option<Value> {
89 if !block.holes.is_empty() {
90 return None;
91 }
92 self.literal_source(block.header.start, block.body.end.max(block.header.end))
93 }
94
95 fn literal_source(&self, start: usize, end: usize) -> Option<Value> {
96 let source = self.source.get(start..end)?.trim();
97 let yaml = serde_yaml::from_str::<serde_yaml::Value>(source).ok()?;
98 serde_json::to_value(yaml).ok()
99 }
100}