1+ use super :: LanguageExtractor ;
2+ use crate :: extractor:: models:: { ChunkType , Language } ;
3+ use crate :: { GitTypeError , Result } ;
4+ use tree_sitter:: { Node , Parser } ;
5+
6+ pub struct PhpExtractor ;
7+
8+ impl LanguageExtractor for PhpExtractor {
9+ fn language ( & self ) -> Language {
10+ Language :: Php
11+ }
12+
13+ fn file_extensions ( & self ) -> & [ & str ] {
14+ & [ "php" , "phtml" , "php3" , "php4" , "php5" ]
15+ }
16+
17+ fn tree_sitter_language ( & self ) -> tree_sitter:: Language {
18+ tree_sitter_php:: language_php ( )
19+ }
20+
21+ fn query_patterns ( & self ) -> & str {
22+ "
23+ (function_definition name: (name) @name) @function
24+ (method_declaration name: (name) @name) @method
25+ (class_declaration name: (name) @name) @class
26+ (interface_declaration name: (name) @name) @interface
27+ (trait_declaration name: (name) @name) @trait
28+ (namespace_definition name: (namespace_name (name) @name)) @namespace
29+ "
30+ }
31+
32+ fn comment_query ( & self ) -> & str {
33+ "
34+ (comment) @comment
35+ "
36+ }
37+
38+ fn capture_name_to_chunk_type ( & self , capture_name : & str ) -> Option < ChunkType > {
39+ match capture_name {
40+ "function" => Some ( ChunkType :: Function ) ,
41+ "method" => Some ( ChunkType :: Function ) ,
42+ "class" => Some ( ChunkType :: Class ) ,
43+ "interface" => Some ( ChunkType :: Class ) ,
44+ "trait" => Some ( ChunkType :: Class ) ,
45+ "namespace" => Some ( ChunkType :: Function ) ,
46+ "name" => None , // name captures are not chunks themselves
47+ _ => None ,
48+ }
49+ }
50+
51+ fn extract_name ( & self , node : Node , source_code : & str , capture_name : & str ) -> Option < String > {
52+ // For @name captures, the node is already the name node
53+ if capture_name == "name" {
54+ let start = node. start_byte ( ) ;
55+ let end = node. end_byte ( ) ;
56+ return Some ( source_code[ start..end] . to_string ( ) ) ;
57+ }
58+
59+ // Fallback to searching for name child
60+ self . extract_name_from_node ( node, source_code)
61+ }
62+ }
63+
64+ impl PhpExtractor {
65+ fn extract_name_from_node ( & self , node : Node , source_code : & str ) -> Option < String > {
66+ let mut cursor = node. walk ( ) ;
67+ if cursor. goto_first_child ( ) {
68+ loop {
69+ let child = cursor. node ( ) ;
70+ if child. kind ( ) == "name" {
71+ let start = child. start_byte ( ) ;
72+ let end = child. end_byte ( ) ;
73+ return Some ( source_code[ start..end] . to_string ( ) ) ;
74+ }
75+ if !cursor. goto_next_sibling ( ) {
76+ break ;
77+ }
78+ }
79+ }
80+ None
81+ }
82+
83+ pub fn create_parser ( ) -> Result < Parser > {
84+ let mut parser = Parser :: new ( ) ;
85+ parser
86+ . set_language ( tree_sitter_php:: language_php ( ) )
87+ . map_err ( |e| {
88+ GitTypeError :: ExtractionFailed ( format ! ( "Failed to set PHP language: {}" , e) )
89+ } ) ?;
90+ Ok ( parser)
91+ }
92+ }
0 commit comments