use crate::indexer::languages::Language;
use tree_sitter::Node;
pub struct Json {}
impl Language for Json {
fn name(&self) -> &'static str {
"json"
}
fn get_ts_language(&self) -> tree_sitter::Language {
tree_sitter_json::LANGUAGE.into()
}
fn get_meaningful_kinds(&self) -> Vec<&'static str> {
vec!["object", "array"]
}
fn extract_symbols(&self, node: Node, contents: &str) -> Vec<String> {
let mut symbols = Vec::new();
if node.kind() == "object" {
self.extract_json_keys(node, contents, &mut symbols);
} else {
self.extract_identifiers(node, contents, &mut symbols);
}
symbols.sort();
symbols.dedup();
symbols
}
fn extract_identifiers(&self, node: Node, contents: &str, symbols: &mut Vec<String>) {
let kind = node.kind();
if kind == "string" {
let parent_kind = node.parent().map(|p| p.kind()).unwrap_or("");
if parent_kind == "pair" {
if let Ok(text) = node.utf8_text(contents.as_bytes()) {
let t = text.trim_matches('"').trim();
if !t.is_empty() && !symbols.contains(&t.to_string()) {
symbols.push(t.to_string());
}
}
}
}
let mut cursor = node.walk();
if cursor.goto_first_child() {
loop {
self.extract_identifiers(cursor.node(), contents, symbols);
if !cursor.goto_next_sibling() {
break;
}
}
}
}
fn are_node_types_equivalent(&self, type1: &str, type2: &str) -> bool {
if type1 == type2 {
return true;
}
let semantic_groups = [
&["object", "array"] as &[&str],
&["string", "number", "true", "false", "null"],
];
for group in &semantic_groups {
let contains_type1 = group.contains(&type1);
let contains_type2 = group.contains(&type2);
if contains_type1 && contains_type2 {
return true;
}
}
false
}
fn get_node_type_description(&self, node_type: &str) -> &'static str {
match node_type {
"object" => "JSON objects",
"array" => "JSON arrays",
"string" => "JSON strings",
"number" => "JSON numbers",
"true" | "false" => "JSON booleans",
"null" => "JSON null values",
"pair" => "JSON key-value pairs",
_ => "JSON structures",
}
}
fn resolve_import(
&self,
_import_path: &str,
_source_file: &str,
_all_files: &[String],
) -> Option<String> {
None
}
fn get_file_extensions(&self) -> Vec<&'static str> {
vec!["json"]
}
}
impl Json {
#[allow(clippy::only_used_in_recursion)]
fn extract_json_keys(&self, node: Node, contents: &str, symbols: &mut Vec<String>) {
for child in node.children(&mut node.walk()) {
if child.kind() == "pair" {
let mut pair_cursor = child.walk();
if pair_cursor.goto_first_child() {
let key_node = pair_cursor.node();
if key_node.kind() == "string" {
if let Ok(text) = key_node.utf8_text(contents.as_bytes()) {
let t = text.trim_matches('"').trim();
if !t.is_empty() && !symbols.contains(&t.to_string()) {
symbols.push(t.to_string());
}
}
}
}
if pair_cursor.goto_next_sibling() && pair_cursor.goto_next_sibling() {
let value_node = pair_cursor.node();
if value_node.kind() == "object" || value_node.kind() == "array" {
self.extract_json_keys(value_node, contents, symbols);
}
}
}
}
}
}