1use crate::{ContainerBody, Import, Language, LanguageSymbols};
4use tree_sitter::Node;
5
6pub struct PowerShell;
8
9impl Language for PowerShell {
10 fn name(&self) -> &'static str {
11 "PowerShell"
12 }
13 fn extensions(&self) -> &'static [&'static str] {
14 &["ps1", "psm1", "psd1"]
15 }
16 fn grammar_name(&self) -> &'static str {
17 "powershell"
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() != "pipeline" {
26 return Vec::new();
27 }
28
29 let text = &content[node.byte_range()];
30 let line = node.start_position().row + 1;
31
32 if let Some(rest) = text.strip_prefix("Import-Module ") {
34 let module = rest.split_whitespace().next().map(|s| s.to_string());
35 if let Some(module) = module {
36 return vec![Import {
37 module,
38 names: Vec::new(),
39 alias: None,
40 is_wildcard: true,
41 is_relative: false,
42 line,
43 }];
44 }
45 }
46
47 Vec::new()
48 }
49
50 fn format_import(&self, import: &Import, _names: Option<&[&str]>) -> String {
51 format!("Import-Module {}", import.module)
53 }
54
55 fn is_test_symbol(&self, symbol: &crate::Symbol) -> bool {
56 let name = symbol.name.as_str();
57 match symbol.kind {
58 crate::SymbolKind::Function | crate::SymbolKind::Method => name.starts_with("test_"),
59 crate::SymbolKind::Module => name == "tests" || name == "test",
60 _ => false,
61 }
62 }
63
64 fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
65 node.child_by_field_name("body")
66 }
67
68 fn analyze_container_body(
69 &self,
70 body_node: &Node,
71 content: &str,
72 inner_indent: &str,
73 ) -> Option<ContainerBody> {
74 crate::body::analyze_brace_body(body_node, content, inner_indent)
75 }
76}
77
78impl LanguageSymbols for PowerShell {}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use crate::validate_unused_kinds_audit;
84
85 #[test]
86 fn unused_node_kinds_audit() {
87 #[rustfmt::skip]
88 let documented_unused: &[&str] = &[
89 "additive_argument_expression", "additive_expression", "argument_expression",
90 "argument_expression_list", "array_expression", "array_literal_expression",
91 "array_type_name", "assignement_operator", "assignment_expression",
92 "bitwise_argument_expression", "bitwise_expression", "block_name", "cast_expression",
93 "catch_clauses", "catch_type_list", "class_attribute", "class_method_definition",
94 "class_method_parameter", "class_method_parameter_list", "class_property_definition",
95 "command_invokation_operator", "comparison_argument_expression",
96 "comparison_expression", "comparison_operator", "data_statement", "do_statement",
97 "else_clause", "elseif_clauses", "empty_statement", "enum_member",
98 "expression_with_unary_operator", "file_redirection_operator", "finally_clause",
99 "flow_control_statement", "for_condition", "for_initializer", "for_iterator",
100 "foreach_command", "foreach_parameter", "format_argument_expression",
101 "format_expression", "format_operator",
102 "function_parameter_declaration", "generic_type_arguments", "generic_type_name",
103 "hash_entry", "hash_literal_body", "hash_literal_expression",
104 "inlinescript_statement", "invokation_expression", "invokation_foreach_expression",
105 "key_expression", "label_expression", "left_assignment_expression",
106 "logical_argument_expression", "logical_expression", "merging_redirection_operator",
107 "multiplicative_argument_expression", "multiplicative_expression", "named_block",
108 "named_block_list", "parallel_statement", "param_block", "parenthesized_expression",
109 "post_decrement_expression", "post_increment_expression", "pre_decrement_expression",
110 "pre_increment_expression", "range_argument_expression", "range_expression",
111 "script_block_body", "script_block_expression", "sequence_statement",
112 "statement_block", "statement_list", "sub_expression", "switch_body",
113 "switch_clause", "switch_clause_condition", "switch_clauses", "trap_statement",
114 "type_identifier", "type_literal", "type_name", "type_spec", "unary_expression",
115 "while_condition",
116 "if_statement",
118 "try_statement",
119 "catch_clause",
120 "while_statement",
121 "switch_statement",
122 "for_statement",
123 "elseif_clause",
124 "foreach_statement",
125 "script_block",
126 ];
127 validate_unused_kinds_audit(&PowerShell, documented_unused)
128 .expect("PowerShell unused node kinds audit failed");
129 }
130}