normalize_languages/
zig.rs1use crate::{Import, Language, LanguageSymbols, Visibility};
4use tree_sitter::Node;
5
6pub struct Zig;
8
9impl Language for Zig {
10 fn name(&self) -> &'static str {
11 "Zig"
12 }
13 fn extensions(&self) -> &'static [&'static str] {
14 &["zig"]
15 }
16 fn grammar_name(&self) -> &'static str {
17 "zig"
18 }
19
20 fn as_symbols(&self) -> Option<&dyn LanguageSymbols> {
21 Some(self)
22 }
23
24 fn extract_imports(&self, node: &Node, content: &str) -> Vec<Import> {
25 if node.kind() != "builtin_call_expression" {
27 return Vec::new();
28 }
29
30 let text = &content[node.byte_range()];
31 if !text.starts_with("@import") {
32 return Vec::new();
33 }
34
35 let mut cursor = node.walk();
37 for child in node.children(&mut cursor) {
38 if child.kind() == "string_literal" {
39 let module = content[child.byte_range()].trim_matches('"').to_string();
40 let is_relative = module.starts_with('.');
41 return vec![Import {
42 module,
43 names: Vec::new(),
44 alias: None,
45 is_wildcard: false,
46 is_relative,
47 line: node.start_position().row + 1,
48 }];
49 }
50 }
51
52 Vec::new()
53 }
54
55 fn format_import(&self, import: &Import, _names: Option<&[&str]>) -> String {
56 format!("@import(\"{}\")", import.module)
58 }
59
60 fn get_visibility(&self, node: &Node, content: &str) -> Visibility {
61 if let Some(prev) = node.prev_sibling() {
63 let text = &content[prev.byte_range()];
64 if text == "pub" {
65 return Visibility::Public;
66 }
67 }
68 let text = &content[node.byte_range()];
70 if text.starts_with("pub ") {
71 Visibility::Public
72 } else {
73 Visibility::Private
74 }
75 }
76
77 fn is_test_symbol(&self, symbol: &crate::Symbol) -> bool {
78 let name = symbol.name.as_str();
79 match symbol.kind {
80 crate::SymbolKind::Function | crate::SymbolKind::Method => name.starts_with("test_"),
81 crate::SymbolKind::Module => name == "tests" || name == "test",
82 _ => false,
83 }
84 }
85
86 fn node_name<'a>(&self, node: &Node, content: &'a str) -> Option<&'a str> {
87 let name_node = node
90 .child_by_field_name("function")
91 .or_else(|| node.child_by_field_name("variable_type_function"))?;
92 Some(&content[name_node.byte_range()])
93 }
94
95 fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
96 node.child_by_field_name("body")
97 }
98}
99
100impl LanguageSymbols for Zig {}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::validate_unused_kinds_audit;
106
107 #[test]
108 fn unused_node_kinds_audit() {
109 #[rustfmt::skip]
110 let documented_unused: &[&str] = &[
111 "ArrayTypeStart", "BUILTINIDENTIFIER", "BitShiftOp", "BlockExpr",
113 "BlockExprStatement", "BlockLabel", "BuildinTypeExpr", "ContainerDeclType",
114 "ForArgumentsList", "ForExpr", "ForItem", "ForPrefix", "ForTypeExpr",
115 "FormatSequence", "IDENTIFIER", "IfExpr", "IfPrefix", "IfTypeExpr",
116 "LabeledStatement", "LabeledTypeExpr", "LoopExpr", "LoopStatement",
117 "LoopTypeExpr", "ParamType", "PrefixTypeOp", "PtrTypeStart",
118 "SliceTypeStart", "Statement", "SwitchCase", "WhileContinueExpr",
119 "WhileExpr", "WhilePrefix", "WhileTypeExpr",
120 "ForStatement",
122 "WhileStatement",
123 "Block",
124 "IfStatement",
125 ];
126 validate_unused_kinds_audit(&Zig, documented_unused)
127 .expect("Zig unused node kinds audit failed");
128 }
129}