normalize_languages/
yaml.rs1use crate::{Language, LanguageSymbols};
4use tree_sitter::Node;
5
6pub struct Yaml;
8
9impl Language for Yaml {
10 fn name(&self) -> &'static str {
11 "YAML"
12 }
13 fn extensions(&self) -> &'static [&'static str] {
14 &["yaml", "yml"]
15 }
16 fn grammar_name(&self) -> &'static str {
17 "yaml"
18 }
19
20 fn as_symbols(&self) -> Option<&dyn LanguageSymbols> {
21 Some(self)
22 }
23
24 fn refine_kind(
25 &self,
26 node: &Node,
27 _content: &str,
28 tag_kind: crate::SymbolKind,
29 ) -> crate::SymbolKind {
30 if node.kind() == "block_mapping_pair"
32 && let Some(value) = node.child_by_field_name("value")
33 {
34 if value.kind() == "block_node" {
36 let mut cursor = value.walk();
37 for child in value.children(&mut cursor) {
38 if child.kind() == "block_mapping" {
39 return crate::SymbolKind::Module;
40 }
41 }
42 }
43 }
44 tag_kind
45 }
46
47 fn node_name<'a>(&self, node: &Node, content: &'a str) -> Option<&'a str> {
48 if node.kind() == "block_mapping_pair"
49 && let Some(key) = node.child_by_field_name("key")
50 {
51 return find_scalar_text(key, content);
52 }
53 None
54 }
55
56 fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
57 if node.kind() == "block_mapping_pair"
58 && let Some(value) = node.child_by_field_name("value")
59 && value.kind() == "block_node"
60 {
61 let mut cursor = value.walk();
62 for child in value.children(&mut cursor) {
63 if child.kind() == "block_mapping" {
64 return Some(child);
65 }
66 }
67 }
68 None
69 }
70
71 fn build_signature(&self, node: &Node, content: &str) -> String {
72 if let Some(key) = self.node_name(node, content) {
73 if let Some(value) = node.child_by_field_name("value") {
74 if value.kind() == "block_node" {
75 return format!("{}:", key);
76 }
77 let val_text = content[value.byte_range()].trim();
78 if val_text.len() > 40 {
79 return format!("{}: {}…", key, &val_text[..37]);
80 }
81 return format!("{}: {}", key, val_text);
82 }
83 return key.to_string();
84 }
85 content[node.byte_range()]
86 .lines()
87 .next()
88 .unwrap_or("")
89 .trim()
90 .to_string()
91 }
92}
93
94impl LanguageSymbols for Yaml {}
95
96fn find_scalar_text<'a>(node: Node, content: &'a str) -> Option<&'a str> {
98 let kind = node.kind();
99 if kind == "string_scalar" || kind == "string_content" {
100 return Some(&content[node.byte_range()]);
101 }
102 let mut cursor = node.walk();
103 for child in node.children(&mut cursor) {
104 if let Some(text) = find_scalar_text(child, content) {
105 return Some(text);
106 }
107 }
108 None
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::validate_unused_kinds_audit;
115
116 #[test]
117 fn unused_node_kinds_audit() {
118 #[rustfmt::skip]
119 let documented_unused: &[&str] = &[
120 "block_node", "block_scalar",
121 "block_sequence", "block_sequence_item",
122 "block_mapping",
124 ];
125 validate_unused_kinds_audit(&Yaml, documented_unused)
126 .expect("YAML unused node kinds audit failed");
127 }
128}