@@ -231,7 +231,7 @@ func (ca *CodeAnalyzer) analyzeFunctionDecl(fset *token.FileSet, fn *doc.Func, a
231231 info .Parameters = ca .extractParameters (fn .Decl .Type .Params )
232232 info .Returns = ca .extractReturns (fn .Decl .Type .Results )
233233 }
234- info .Calls = ca .extractCallsFromAST (astBody )
234+ info .Calls , info . TemplateFiles = ca .extractCallsFromAST (astBody )
235235 } else if fn .Decl != nil {
236236 // Fallback to doc.Func Decl (won't have Body)
237237 // Extract position information
@@ -761,6 +761,24 @@ func convertPackageInfoToChunks(pi *PackageInfo) []CodeChunk {
761761 Type : pkgParser .RelCalls ,
762762 })
763763 }
764+ // Template file dependencies: template.ParseFiles("layout.html") → RelDependency
765+ for _ , tplFile := range fn .TemplateFiles {
766+ rels = append (rels , pkgParser.Relation {
767+ TargetName : tplFile ,
768+ Type : pkgParser .RelDependency ,
769+ })
770+ }
771+
772+ metadata := map [string ]any {
773+ "receiver" : fn .Receiver ,
774+ "is_method" : fn .IsMethod ,
775+ "params" : fn .Parameters ,
776+ "returns" : fn .Returns ,
777+ "examples" : fn .Examples ,
778+ }
779+ if len (fn .TemplateFiles ) > 0 {
780+ metadata ["template_files" ] = fn .TemplateFiles
781+ }
764782
765783 out = append (out , CodeChunk {
766784 Type : kind ,
@@ -774,13 +792,7 @@ func convertPackageInfoToChunks(pi *PackageInfo) []CodeChunk {
774792 Docstring : fn .Description ,
775793 Code : fn .Code ,
776794 Relations : rels ,
777- Metadata : map [string ]any {
778- "receiver" : fn .Receiver ,
779- "is_method" : fn .IsMethod ,
780- "params" : fn .Parameters ,
781- "returns" : fn .Returns ,
782- "examples" : fn .Examples ,
783- },
795+ Metadata : metadata ,
784796 })
785797 }
786798
@@ -925,29 +937,52 @@ func (ca *CodeAnalyzer) extractCodeFromFile(filePath string, startLine, endLine
925937 return strings .Join (lines , "\n " ), nil
926938}
927939
928- func (ca * CodeAnalyzer ) extractCallsFromAST (body * ast.BlockStmt ) []string {
940+ func (ca * CodeAnalyzer ) extractCallsFromAST (body * ast.BlockStmt ) ( []string , [] string ) {
929941 if body == nil {
930- return nil
942+ return nil , nil
931943 }
932944 var calls []string
945+ var templateFiles []string
933946 seen := make (map [string ]bool )
947+ seenTpl := make (map [string ]bool )
948+
949+ // Template-related function names that receive file paths as string arguments.
950+ templateFuncs := map [string ]bool {
951+ "ParseFiles" : true , "ParseGlob" : true ,
952+ }
934953
935954 ast .Inspect (body , func (n ast.Node ) bool {
936955 if call , ok := n .(* ast.CallExpr ); ok {
937956 var name string
957+ var sel string // selector part (e.g. "template" in template.ParseFiles)
938958 switch fun := call .Fun .(type ) {
939959 case * ast.Ident :
940960 name = fun .Name
941961 case * ast.SelectorExpr :
942962 x := ca .typeToString (fun .X )
943- name = fmt .Sprintf ("%s.%s" , x , fun .Sel .Name )
963+ sel = fun .Sel .Name
964+ name = fmt .Sprintf ("%s.%s" , x , sel )
944965 }
945966 if name != "" && ! seen [name ] {
946967 calls = append (calls , name )
947968 seen [name ] = true
948969 }
970+
971+ // Extract template file paths from template.ParseFiles("a.html", "b.html")
972+ // and similar calls (works on any receiver: t.ParseFiles, tpl.ParseFiles, etc.)
973+ if templateFuncs [sel ] {
974+ for _ , arg := range call .Args {
975+ if lit , ok := arg .(* ast.BasicLit ); ok && lit .Kind == token .STRING {
976+ path := strings .Trim (lit .Value , "\" `" )
977+ if path != "" && ! seenTpl [path ] {
978+ seenTpl [path ] = true
979+ templateFiles = append (templateFiles , path )
980+ }
981+ }
982+ }
983+ }
949984 }
950985 return true
951986 })
952- return calls
987+ return calls , templateFiles
953988}
0 commit comments