normalize_languages/
yuri.rs1use crate::external_packages::ResolvedPackage;
4use crate::{Export, Import, Language, Symbol, Visibility, VisibilityMechanism};
5use std::path::{Path, PathBuf};
6use tree_sitter::Node;
7
8pub struct Yuri;
10
11impl Language for Yuri {
12 fn name(&self) -> &'static str {
13 "Yuri"
14 }
15 fn extensions(&self) -> &'static [&'static str] {
16 &["yuri"]
17 }
18 fn grammar_name(&self) -> &'static str {
19 "yuri"
20 }
21
22 fn has_symbols(&self) -> bool {
23 true
24 }
25
26 fn container_kinds(&self) -> &'static [&'static str] {
27 &[]
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
42 fn visibility_mechanism(&self) -> VisibilityMechanism {
43 VisibilityMechanism::AllPublic
44 }
45
46 fn extract_public_symbols(&self, _node: &Node, _content: &str) -> Vec<Export> {
47 Vec::new()
48 }
49
50 fn scope_creating_kinds(&self) -> &'static [&'static str] {
51 &[]
52 }
53 fn control_flow_kinds(&self) -> &'static [&'static str] {
54 &[]
55 }
56 fn complexity_nodes(&self) -> &'static [&'static str] {
57 &[]
58 }
59 fn nesting_nodes(&self) -> &'static [&'static str] {
60 &[]
61 }
62
63 fn signature_suffix(&self) -> &'static str {
64 ""
65 }
66
67 fn extract_function(
68 &self,
69 _node: &Node,
70 _content: &str,
71 _in_container: bool,
72 ) -> Option<Symbol> {
73 None
74 }
75 fn extract_container(&self, _node: &Node, _content: &str) -> Option<Symbol> {
76 None
77 }
78 fn extract_type(&self, _node: &Node, _content: &str) -> Option<Symbol> {
79 None
80 }
81 fn extract_docstring(&self, _node: &Node, _content: &str) -> Option<String> {
82 None
83 }
84
85 fn extract_attributes(&self, _node: &Node, _content: &str) -> Vec<String> {
86 Vec::new()
87 }
88 fn extract_imports(&self, _node: &Node, _content: &str) -> Vec<Import> {
89 Vec::new()
90 }
91
92 fn format_import(&self, _import: &Import, _names: Option<&[&str]>) -> String {
93 String::new()
95 }
96
97 fn is_public(&self, _node: &Node, _content: &str) -> bool {
98 true
99 }
100 fn get_visibility(&self, _node: &Node, _content: &str) -> Visibility {
101 Visibility::Public
102 }
103
104 fn is_test_symbol(&self, symbol: &crate::Symbol) -> bool {
105 let name = symbol.name.as_str();
106 match symbol.kind {
107 crate::SymbolKind::Function | crate::SymbolKind::Method => name.starts_with("test_"),
108 crate::SymbolKind::Module => name == "tests" || name == "test",
109 _ => false,
110 }
111 }
112
113 fn embedded_content(&self, _node: &Node, _content: &str) -> Option<crate::EmbeddedBlock> {
114 None
115 }
116
117 fn container_body<'a>(&self, _node: &'a Node<'a>) -> Option<Node<'a>> {
118 None
119 }
120
121 fn body_has_docstring(&self, _body: &Node, _content: &str) -> bool {
122 false
123 }
124
125 fn node_name<'a>(&self, node: &Node, content: &'a str) -> Option<&'a str> {
126 node.child_by_field_name("name")
127 .map(|n| &content[n.byte_range()])
128 }
129
130 fn file_path_to_module_name(&self, path: &Path) -> Option<String> {
131 let ext = path.extension()?.to_str()?;
132 if ext != "yuri" {
133 return None;
134 }
135 let stem = path.file_stem()?.to_str()?;
136 Some(stem.to_string())
137 }
138
139 fn module_name_to_paths(&self, module: &str) -> Vec<String> {
140 vec![format!("{}.yuri", module)]
141 }
142
143 fn lang_key(&self) -> &'static str {
144 "yuri"
145 }
146
147 fn is_stdlib_import(&self, _: &str, _: &Path) -> bool {
148 false
149 }
150 fn find_stdlib(&self, _: &Path) -> Option<PathBuf> {
151 None
152 }
153 fn resolve_local_import(&self, _: &str, _: &Path, _: &Path) -> Option<PathBuf> {
154 None
155 }
156 fn resolve_external_import(&self, _: &str, _: &Path) -> Option<ResolvedPackage> {
157 None
158 }
159 fn get_version(&self, _: &Path) -> Option<String> {
160 None
161 }
162 fn find_package_cache(&self, _: &Path) -> Option<PathBuf> {
163 None
164 }
165 fn indexable_extensions(&self) -> &'static [&'static str] {
166 &["yuri"]
167 }
168 fn package_sources(&self, _: &Path) -> Vec<crate::PackageSource> {
169 Vec::new()
170 }
171
172 fn should_skip_package_entry(&self, name: &str, is_dir: bool) -> bool {
173 use crate::traits::{has_extension, skip_dotfiles};
174 if skip_dotfiles(name) {
175 return true;
176 }
177 !is_dir && !has_extension(name, self.indexable_extensions())
178 }
179
180 fn discover_packages(&self, _: &crate::PackageSource) -> Vec<(String, PathBuf)> {
181 Vec::new()
182 }
183
184 fn package_module_name(&self, entry_name: &str) -> String {
185 entry_name
186 .strip_suffix(".yuri")
187 .unwrap_or(entry_name)
188 .to_string()
189 }
190
191 fn find_package_entry(&self, path: &Path) -> Option<PathBuf> {
192 if path.is_file() {
193 Some(path.to_path_buf())
194 } else {
195 None
196 }
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203 use crate::validate_unused_kinds_audit;
204
205 #[test]
206 fn unused_node_kinds_audit() {
207 #[rustfmt::skip]
208 let documented_unused: &[&str] = &[
209 "function_item", "function_parameters", "module_item", "import_item",
211 "type_alias_item", "compound_type_item", "compound_type_field",
213 "array_type_item", "primitive_type",
214 "break_statement", "continue_statement", "return_statement",
216 "else_clause",
217 "if_expression", "binary_expression", "unary_expression",
219 "call_expression", "paren_expression", "array_expression",
220 "compound_value_expression",
221 "block", "identifier",
223 ];
224 validate_unused_kinds_audit(&Yuri, documented_unused)
225 .expect("Yuri unused node kinds audit failed");
226 }
227}