normalize_languages/
graphql.rs1use crate::{ContainerBody, Language, LanguageSymbols};
4use tree_sitter::Node;
5
6pub struct GraphQL;
8
9impl GraphQL {
10 fn collect_named_types(node: &Node, out: &mut Vec<String>, content: &str) {
13 if node.kind() == "named_type" {
14 for i in 0..node.child_count() {
16 if let Some(child) = node.child(i as u32)
17 && child.is_named()
18 {
19 out.push(content[child.byte_range()].to_string());
20 return;
21 }
22 }
23 return;
24 }
25 for i in 0..node.child_count() {
26 if let Some(child) = node.child(i as u32) {
27 Self::collect_named_types(&child, out, content);
28 }
29 }
30 }
31}
32
33impl Language for GraphQL {
34 fn name(&self) -> &'static str {
35 "GraphQL"
36 }
37 fn extensions(&self) -> &'static [&'static str] {
38 &["graphql", "gql"]
39 }
40 fn grammar_name(&self) -> &'static str {
41 "graphql"
42 }
43
44 fn as_symbols(&self) -> Option<&dyn LanguageSymbols> {
45 Some(self)
46 }
47
48 fn build_signature(&self, node: &Node, content: &str) -> String {
49 let name = self.node_name(node, content).unwrap_or("");
50 let keyword = match node.kind() {
51 "interface_type_definition" => "interface",
52 "enum_type_definition" => "enum",
53 "union_type_definition" => "union",
54 "input_object_type_definition" => "input",
55 "scalar_type_definition" => "scalar",
56 _ => "type",
57 };
58 format!("{} {}", keyword, name)
59 }
60
61 fn extract_implements(&self, node: &Node, content: &str) -> crate::ImplementsInfo {
62 let mut implements = Vec::new();
63 for i in 0..node.child_count() {
64 if let Some(child) = node.child(i as u32)
65 && child.kind() == "implements_interfaces"
66 {
67 GraphQL::collect_named_types(&child, &mut implements, content);
68 }
69 }
70 crate::ImplementsInfo {
71 is_interface: false,
72 implements,
73 }
74 }
75
76 fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
77 node.child_by_field_name("fields_definition")
78 }
79
80 fn analyze_container_body(
81 &self,
82 body_node: &Node,
83 content: &str,
84 inner_indent: &str,
85 ) -> Option<ContainerBody> {
86 crate::body::analyze_brace_body(body_node, content, inner_indent)
88 }
89
90 fn node_name<'a>(&self, node: &Node, content: &'a str) -> Option<&'a str> {
91 if let Some(n) = node.child_by_field_name("name") {
92 return Some(&content[n.byte_range()]);
93 }
94 for i in 0..node.child_count() {
96 if let Some(child) = node.child(i as u32)
97 && child.kind() == "name"
98 {
99 return Some(&content[child.byte_range()]);
100 }
101 }
102 None
103 }
104}
105
106impl LanguageSymbols for GraphQL {}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::validate_unused_kinds_audit;
112
113 #[test]
114 fn unused_node_kinds_audit() {
115 #[rustfmt::skip]
117 let documented_unused: &[&str] = &[
118 "argument", "directive", "enum_value", "enum_value_definition",
119 "enum_values_definition", "executable_definition", "field",
120 "fields_definition", "fragment_spread",
121 "implements_interfaces", "inline_fragment", "input_fields_definition",
122 "input_value_definition", "named_type", "type", "type_condition",
123 "type_definition", "type_extension", "type_system_definition",
124 "type_system_extension", "union_member_types", "variable_definition",
125 "arguments_definition", "definition", "directive_definition", "list_type",
126 "non_null_type", "object_type_extension", "operation_type",
127 "root_operation_type_definition", "scalar_type_extension", "schema_definition",
128 "enum_type_extension", "input_object_type_extension", "interface_type_extension",
129 "type_system_directive_location", "union_type_extension", "variable_definitions",
130 ];
131 validate_unused_kinds_audit(&GraphQL, documented_unused)
132 .expect("GraphQL unused node kinds audit failed");
133 }
134}