qex_core/chunk/languages/
javascript.rs1use super::{extract_preceding_comments, find_child_text, find_name, LanguageChunker, NodeMetadata};
2use crate::chunk::ChunkType;
3
4pub struct JavaScriptChunker;
5
6impl LanguageChunker for JavaScriptChunker {
7 fn tree_sitter_language(&self) -> tree_sitter::Language {
8 tree_sitter_javascript::LANGUAGE.into()
9 }
10
11 fn language_name(&self) -> &str {
12 "javascript"
13 }
14
15 fn file_extensions(&self) -> &[&str] {
16 &["js", "jsx", "mjs", "cjs"]
17 }
18
19 fn is_splittable(&self, node_type: &str) -> bool {
20 matches!(
21 node_type,
22 "function_declaration"
23 | "class_declaration"
24 | "method_definition"
25 | "arrow_function"
26 | "generator_function"
27 | "generator_function_declaration"
28 | "export_statement"
29 | "lexical_declaration"
30 )
31 }
32
33 fn has_nested_chunks(&self, node_type: &str) -> bool {
34 matches!(node_type, "class_declaration" | "export_statement")
35 }
36
37 fn classify_node(&self, node_type: &str, parent_name: Option<&str>) -> ChunkType {
38 match node_type {
39 "class_declaration" => ChunkType::Class,
40 "method_definition" => ChunkType::Method,
41 "function_declaration" | "generator_function_declaration" => {
42 if parent_name.is_some() {
43 ChunkType::Method
44 } else {
45 ChunkType::Function
46 }
47 }
48 "arrow_function" | "generator_function" => ChunkType::Function,
49 "export_statement" | "lexical_declaration" => ChunkType::ModuleLevel,
50 _ => ChunkType::ModuleLevel,
51 }
52 }
53
54 fn extract_metadata(&self, node: tree_sitter::Node, source: &str) -> NodeMetadata {
55 let mut meta = NodeMetadata::default();
56
57 match node.kind() {
58 "function_declaration" | "generator_function_declaration" => {
59 meta.name = find_name(node, source);
60 meta.is_async = source[node.start_byte()..node.end_byte()].starts_with("async ");
61 meta.is_generator = node.kind().contains("generator");
62 meta.docstring = extract_preceding_comments(node, source);
63 }
64 "class_declaration" => {
65 meta.name = find_name(node, source);
66 meta.docstring = extract_preceding_comments(node, source);
67 }
68 "method_definition" => {
69 meta.name = find_child_text(node, source, "property_identifier");
70 meta.docstring = extract_preceding_comments(node, source);
71 }
72 "arrow_function" => {
73 meta.docstring = extract_preceding_comments(node, source);
76 }
77 "export_statement" => {
78 let mut cursor = node.walk();
80 for child in node.children(&mut cursor) {
81 if child.kind() == "function_declaration" || child.kind() == "class_declaration" {
82 meta.name = find_name(child, source);
83 } else if child.kind() == "lexical_declaration" {
84 let mut inner = child.walk();
86 for decl in child.children(&mut inner) {
87 if decl.kind() == "variable_declarator" {
88 meta.name = find_name(decl, source);
89 break;
90 }
91 }
92 }
93 }
94 meta.docstring = extract_preceding_comments(node, source);
95 }
96 "lexical_declaration" => {
97 let mut cursor = node.walk();
98 for child in node.children(&mut cursor) {
99 if child.kind() == "variable_declarator" {
100 meta.name = find_name(child, source);
101 let mut inner = child.walk();
103 for val in child.children(&mut inner) {
104 if val.kind() == "arrow_function" {
105 meta.is_async = source[val.start_byte()..val.end_byte()].starts_with("async ");
106 }
107 }
108 break;
109 }
110 }
111 meta.docstring = extract_preceding_comments(node, source);
112 }
113 _ => {
114 meta.name = find_name(node, source);
115 meta.docstring = extract_preceding_comments(node, source);
116 }
117 }
118
119 meta
120 }
121}