normalize_languages/
xml.rs1use crate::external_packages::ResolvedPackage;
4use crate::{Export, Import, Language, Symbol, SymbolKind, Visibility, VisibilityMechanism};
5use std::path::{Path, PathBuf};
6use tree_sitter::Node;
7
8pub struct Xml;
10
11impl Language for Xml {
12 fn name(&self) -> &'static str {
13 "XML"
14 }
15 fn extensions(&self) -> &'static [&'static str] {
16 &["xml", "xsl", "xslt", "xsd", "svg", "plist"]
17 }
18 fn grammar_name(&self) -> &'static str {
19 "xml"
20 }
21
22 fn has_symbols(&self) -> bool {
23 false
24 }
25
26 fn container_kinds(&self) -> &'static [&'static str] {
27 &["element"]
28 }
29 fn function_kinds(&self) -> &'static [&'static str] {
30 &[]
31 }
32 fn type_kinds(&self) -> &'static [&'static str] {
33 &[]
34 }
35 fn import_kinds(&self) -> &'static [&'static str] {
36 &[]
37 }
38 fn public_symbol_kinds(&self) -> &'static [&'static str] {
39 &[]
40 }
41 fn visibility_mechanism(&self) -> VisibilityMechanism {
42 VisibilityMechanism::NotApplicable
43 }
44 fn scope_creating_kinds(&self) -> &'static [&'static str] {
45 &[]
46 }
47 fn control_flow_kinds(&self) -> &'static [&'static str] {
48 &[]
49 }
50 fn complexity_nodes(&self) -> &'static [&'static str] {
51 &[]
52 }
53 fn nesting_nodes(&self) -> &'static [&'static str] {
54 &["element"]
55 }
56
57 fn signature_suffix(&self) -> &'static str {
58 ""
59 }
60
61 fn extract_function(
62 &self,
63 _node: &Node,
64 _content: &str,
65 _in_container: bool,
66 ) -> Option<Symbol> {
67 None
68 }
69
70 fn extract_container(&self, node: &Node, content: &str) -> Option<Symbol> {
71 if node.kind() != "element" {
72 return None;
73 }
74
75 let mut cursor = node.walk();
77 for child in node.children(&mut cursor) {
78 if child.kind() == "start_tag" || child.kind() == "self_closing_tag" {
79 let mut inner_cursor = child.walk();
80 for inner in child.children(&mut inner_cursor) {
81 if inner.kind() == "tag_name" {
82 let name = content[inner.byte_range()].to_string();
83 return Some(Symbol {
84 name: name.clone(),
85 kind: SymbolKind::Module,
86 signature: format!("<{}>", name),
87 docstring: None,
88 attributes: Vec::new(),
89 start_line: node.start_position().row + 1,
90 end_line: node.end_position().row + 1,
91 visibility: Visibility::Public,
92 children: Vec::new(),
93 is_interface_impl: false,
94 implements: Vec::new(),
95 });
96 }
97 }
98 }
99 }
100 None
101 }
102
103 fn extract_type(&self, _node: &Node, _content: &str) -> Option<Symbol> {
104 None
105 }
106 fn extract_docstring(&self, _node: &Node, _content: &str) -> Option<String> {
107 None
108 }
109
110 fn extract_attributes(&self, _node: &Node, _content: &str) -> Vec<String> {
111 Vec::new()
112 }
113 fn extract_imports(&self, _node: &Node, _content: &str) -> Vec<Import> {
114 Vec::new()
115 }
116
117 fn format_import(&self, _import: &Import, _names: Option<&[&str]>) -> String {
118 String::new()
120 }
121 fn extract_public_symbols(&self, _node: &Node, _content: &str) -> Vec<Export> {
122 Vec::new()
123 }
124
125 fn is_public(&self, _node: &Node, _content: &str) -> bool {
126 true
127 }
128 fn get_visibility(&self, _node: &Node, _content: &str) -> Visibility {
129 Visibility::Public
130 }
131
132 fn is_test_symbol(&self, _symbol: &crate::Symbol) -> bool {
133 false
134 }
135
136 fn embedded_content(&self, _node: &Node, _content: &str) -> Option<crate::EmbeddedBlock> {
137 None
138 }
139
140 fn container_body<'a>(&self, _node: &'a Node<'a>) -> Option<Node<'a>> {
141 None
142 }
143 fn body_has_docstring(&self, _body: &Node, _content: &str) -> bool {
144 false
145 }
146 fn node_name<'a>(&self, _node: &Node, _content: &'a str) -> Option<&'a str> {
147 None
148 }
149
150 fn file_path_to_module_name(&self, _: &Path) -> Option<String> {
151 None
152 }
153 fn module_name_to_paths(&self, _: &str) -> Vec<String> {
154 Vec::new()
155 }
156
157 fn lang_key(&self) -> &'static str {
158 ""
159 }
160 fn resolve_local_import(&self, _: &str, _: &Path, _: &Path) -> Option<PathBuf> {
161 None
162 }
163 fn resolve_external_import(&self, _: &str, _: &Path) -> Option<ResolvedPackage> {
164 None
165 }
166 fn is_stdlib_import(&self, _: &str, _: &Path) -> bool {
167 false
168 }
169 fn get_version(&self, _: &Path) -> Option<String> {
170 None
171 }
172 fn find_package_cache(&self, _: &Path) -> Option<PathBuf> {
173 None
174 }
175 fn indexable_extensions(&self) -> &'static [&'static str] {
176 &[]
177 }
178 fn find_stdlib(&self, _: &Path) -> Option<PathBuf> {
179 None
180 }
181 fn package_module_name(&self, name: &str) -> String {
182 name.to_string()
183 }
184 fn package_sources(&self, _: &Path) -> Vec<crate::PackageSource> {
185 Vec::new()
186 }
187 fn discover_packages(&self, _: &crate::PackageSource) -> Vec<(String, PathBuf)> {
188 Vec::new()
189 }
190 fn find_package_entry(&self, _: &Path) -> Option<PathBuf> {
191 None
192 }
193
194 fn should_skip_package_entry(&self, name: &str, is_dir: bool) -> bool {
195 use crate::traits::{has_extension, skip_dotfiles};
196 if skip_dotfiles(name) {
197 return true;
198 }
199 !is_dir && !has_extension(name, self.indexable_extensions())
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use crate::validate_unused_kinds_audit;
207
208 #[test]
209 fn unused_node_kinds_audit() {
210 #[rustfmt::skip]
211 let documented_unused: &[&str] = &[
212 "Enumeration", "NotationType", "StringType", "TokenizedType",
213 "doctypedecl",
214 ];
215 validate_unused_kinds_audit(&Xml, documented_unused)
216 .expect("XML unused node kinds audit failed");
217 }
218}