use crate::{ContainerBody, Import, Language, LanguageSymbols};
use tree_sitter::Node;
pub struct PowerShell;
impl Language for PowerShell {
fn name(&self) -> &'static str {
"PowerShell"
}
fn extensions(&self) -> &'static [&'static str] {
&["ps1", "psm1", "psd1"]
}
fn grammar_name(&self) -> &'static str {
"powershell"
}
fn as_symbols(&self) -> Option<&dyn LanguageSymbols> {
Some(self)
}
fn extract_imports(&self, node: &Node, content: &str) -> Vec<Import> {
if node.kind() != "pipeline" {
return Vec::new();
}
let text = &content[node.byte_range()];
let line = node.start_position().row + 1;
if let Some(rest) = text.strip_prefix("Import-Module ") {
let module = rest.split_whitespace().next().map(|s| s.to_string());
if let Some(module) = module {
return vec![Import {
module,
names: Vec::new(),
alias: None,
is_wildcard: true,
is_relative: false,
line,
}];
}
}
Vec::new()
}
fn format_import(&self, import: &Import, _names: Option<&[&str]>) -> String {
format!("Import-Module {}", import.module)
}
fn is_test_symbol(&self, symbol: &crate::Symbol) -> bool {
let name = symbol.name.as_str();
match symbol.kind {
crate::SymbolKind::Function | crate::SymbolKind::Method => name.starts_with("test_"),
crate::SymbolKind::Module => name == "tests" || name == "test",
_ => false,
}
}
fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
node.child_by_field_name("body")
}
fn analyze_container_body(
&self,
body_node: &Node,
content: &str,
inner_indent: &str,
) -> Option<ContainerBody> {
crate::body::analyze_brace_body(body_node, content, inner_indent)
}
}
impl LanguageSymbols for PowerShell {}
#[cfg(test)]
mod tests {
use super::*;
use crate::validate_unused_kinds_audit;
#[test]
fn unused_node_kinds_audit() {
#[rustfmt::skip]
let documented_unused: &[&str] = &[
"additive_argument_expression", "additive_expression", "argument_expression",
"argument_expression_list", "array_expression", "array_literal_expression",
"array_type_name", "assignement_operator", "assignment_expression",
"bitwise_argument_expression", "bitwise_expression", "block_name", "cast_expression",
"catch_clauses", "catch_type_list", "class_attribute", "class_method_definition",
"class_method_parameter", "class_method_parameter_list", "class_property_definition",
"command_invokation_operator", "comparison_argument_expression",
"comparison_expression", "comparison_operator", "data_statement", "do_statement",
"else_clause", "elseif_clauses", "empty_statement", "enum_member",
"expression_with_unary_operator", "file_redirection_operator", "finally_clause",
"flow_control_statement", "for_condition", "for_initializer", "for_iterator",
"foreach_command", "foreach_parameter", "format_argument_expression",
"format_expression", "format_operator",
"function_parameter_declaration", "generic_type_arguments", "generic_type_name",
"hash_entry", "hash_literal_body", "hash_literal_expression",
"inlinescript_statement", "invokation_expression", "invokation_foreach_expression",
"key_expression", "label_expression", "left_assignment_expression",
"logical_argument_expression", "logical_expression", "merging_redirection_operator",
"multiplicative_argument_expression", "multiplicative_expression", "named_block",
"named_block_list", "parallel_statement", "param_block", "parenthesized_expression",
"post_decrement_expression", "post_increment_expression", "pre_decrement_expression",
"pre_increment_expression", "range_argument_expression", "range_expression",
"script_block_body", "script_block_expression", "sequence_statement",
"statement_block", "statement_list", "sub_expression", "switch_body",
"switch_clause", "switch_clause_condition", "switch_clauses", "trap_statement",
"type_identifier", "type_literal", "type_name", "type_spec", "unary_expression",
"while_condition",
"if_statement",
"try_statement",
"catch_clause",
"while_statement",
"switch_statement",
"for_statement",
"elseif_clause",
"foreach_statement",
"script_block",
];
validate_unused_kinds_audit(&PowerShell, documented_unused)
.expect("PowerShell unused node kinds audit failed");
}
}