feat(html): add Go template parser with structural analysis#47
Open
feat(html): add Go template parser with structural analysis#47
Conversation
Add GoTemplateAnalyzer that parses Go template syntax ({{ }}) in HTML,
.tmpl, and .gohtml files. Extracts directives (define, block, template,
range, if/else, with), variables, custom functions, and comments.
Key features:
- Regex-based parser similar to BladeAnalyzer
- Converts to parser.Symbol with RelDependency relations
({{ template "x" }} creates dependency to template x)
- Dual-mode analysis: Go template + HTML DOM for all file types
- Detects {{ }} syntax automatically regardless of extension
- Stack-based EndLine tracking for nested blocks
- Rich metadata: variables, custom_funcs, ranges, blocks
Files added:
- pkg/parser/html/gotemplate/types.go - Type definitions
- pkg/parser/html/gotemplate/analyzer.go - GoTemplateAnalyzer (regex)
- pkg/parser/html/gotemplate/adapter.go - GoTemplate → Symbol conversion
- pkg/parser/html/gotemplate/testdata/ - Test fixtures
Files modified:
- pkg/parser/html/analyzer.go - Integrate gotemplate + .tmpl/.gohtml
- pkg/parser/html/analyzer_test.go - Integration tests
17/17 tests passing
There was a problem hiding this comment.
Pull request overview
Adds semantic indexing for Go html/template directives embedded in HTML-like files so ragcode can extract template structure (defines/includes/blocks/etc.) instead of treating {{ ... }} as plain text.
Changes:
- Introduces
pkg/parser/html/gotemplatesub-package (types, regex analyzer, symbol adapter) + unit tests/testdata. - Extends the HTML analyzer to recognize
.tmpl/.gohtmland to run Go-template analysis when{{is present. - Adds integration tests covering Go-template-in-HTML and new extensions.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/parser/html/gotemplate/types.go | Defines parsed directive/container types for Go template extraction. |
| pkg/parser/html/gotemplate/analyzer.go | Regex-based Go template directive extraction + block end-line tracking. |
| pkg/parser/html/gotemplate/adapter.go | Converts parsed templates into parser.Symbols + dependency relations/metadata. |
| pkg/parser/html/gotemplate/analyzer_test.go | Unit tests for directive extraction across sample templates. |
| pkg/parser/html/gotemplate/adapter_test.go | Unit tests for symbol conversion, metadata, and relations. |
| pkg/parser/html/gotemplate/testdata/layout.html | Sample template with define/include/block/range/if/with/comment. |
| pkg/parser/html/gotemplate/testdata/page.tmpl | Sample template with template include + define/range/custom funcs. |
| pkg/parser/html/gotemplate/testdata/partial.gohtml | Sample template with nested if/range and variables. |
| pkg/parser/html/analyzer.go | Adds .tmpl/.gohtml handling and dual Go-template + HTML DOM analysis. |
| pkg/parser/html/analyzer_test.go | Integration tests for Go template detection and new extensions. |
You can also share your feedback on Copilot code review. Take the survey.
Comment on lines
+13
to
+14
| reBlock = regexp.MustCompile(`\{\{-?\s*block\s+"([^"]+)"\s*(\.[\w.]*)?`) | ||
| reTemplate = regexp.MustCompile(`\{\{-?\s*template\s+"([^"]+)"\s*(\.[\w.]*)?`) |
Comment on lines
+15
to
+18
| reRange = regexp.MustCompile(`\{\{-?\s*range\s+(\.[\w.]+)`) | ||
| reIf = regexp.MustCompile(`\{\{-?\s*if\s+(.+?)\s*-?\}\}`) | ||
| reElse = regexp.MustCompile(`\{\{-?\s*else\s*-?\}\}`) | ||
| reWith = regexp.MustCompile(`\{\{-?\s*with\s+(\.[\w.]+)`) |
Comment on lines
+137
to
+138
| // {{ else }} | ||
| if reElse.MatchString(line) { |
Comment on lines
+43
to
+47
| for _, fp := range filePaths { | ||
| tpl, err := a.analyzeFile(fp) | ||
| if err != nil { | ||
| continue // skip unreadable files | ||
| } |
Comment on lines
+56
to
+75
| // For single files: detect Go template syntax and run GoTemplate analysis | ||
| info, err := os.Stat(path) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if !info.IsDir() { | ||
| data, err := os.ReadFile(path) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| // If Go template syntax detected, run Go template analysis first | ||
| if bytes.Contains(data, []byte("{{")) { | ||
| goTplAnalyzer := &gotemplate.GoTemplateAnalyzer{} | ||
| templates := goTplAnalyzer.Analyze([]string{path}) | ||
| symbols = append(symbols, gotemplate.ConvertToSymbols(templates)...) | ||
| } | ||
| } | ||
|
|
| ) | ||
|
|
||
| // ConvertToSymbols converts parsed GoTemplate results to parser.Symbol entries | ||
| // with structural relations (dependency for {{ template }}, inheritance-like for {{ block }}). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Add semantic indexing for Go template syntax (
{{ }}) in HTML,.tmpl, and.gohtmlfiles.Previously, ragcode indexed HTML files containing Go templates as plain text — it understood the HTML DOM structure (via goquery) but completely ignored Go template directives like
{{ define }},{{ template }},{{ range }},{{ if }}, etc. Additionally,.tmpland.gohtmlfiles were not recognized at all.What's included
{{ define }},{{ block }},{{ template }},{{ range }},{{ if/else }},{{ with }},{{ .Variable }},{{ funcName }},{{/* comments */}}GoTemplatestructs toparser.Symbolwith:RelDependencyrelations ({{ template "nav" }}→ dependency to "nav"){{ define "name" }}gets its own symbol){{in file content regardless of extension (.html,.tmpl,.gohtml){{ }}) continue to work as beforeArchitecture decision
Implemented as a sub-package
pkg/parser/html/gotemplate/because:.tmpl/.gohtmlfiles already contain HTML — both analyses are valuable{{presence), not extension-basedBladeAnalyzerinpkg/parser/php/laravel/Files Changed
pkg/parser/html/gotemplate/types.gopkg/parser/html/gotemplate/analyzer.gopkg/parser/html/gotemplate/adapter.gopkg/parser/html/gotemplate/analyzer_test.gopkg/parser/html/gotemplate/testdata/pkg/parser/html/analyzer.gopkg/parser/html/analyzer_test.goType of change
Checklist:
go fmt ./...go test ./...and they pass