Skip to content

Commit f4ecffc

Browse files
committed
Merge remote-tracking branch 'origin/dev' into feat/blade-template-indexing
# Conflicts: # pkg/parser/php/laravel/adapter.go # pkg/parser/php/laravel/blade.go # pkg/parser/php/laravel/enricher.go # pkg/parser/php/laravel/types.go
2 parents d198643 + 1fcaca2 commit f4ecffc

10 files changed

Lines changed: 90 additions & 12 deletions

File tree

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
- name: Set up Go
4141
uses: actions/setup-go@v5
4242
with:
43-
go-version: '1.22'
43+
go-version: '1.24'
4444
cache: true
4545

4646
- name: Run GoReleaser

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
- name: Set up Go
1919
uses: actions/setup-go@v5
2020
with:
21-
go-version: '1.22'
21+
go-version: '1.24'
2222
cache: true
2323

2424
- name: Download dependencies
@@ -54,7 +54,7 @@
5454
- name: Set up Go
5555
uses: actions/setup-go@v5
5656
with:
57-
go-version: '1.22'
57+
go-version: '1.24'
5858
cache: true
5959

6060
- name: golangci-lint

pkg/parser/php/laravel/adapter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ func (a *Adapter) convertBladeToChunks(templates []BladeTemplate) []php.CodeChun
299299

300300
// EndLine defaults to TotalLines (whole template), fallback to 1 for empty files
301301
endLine := tpl.TotalLines
302-
if endLine == 0 {
302+
if endLine < 1 {
303303
endLine = 1
304304
}
305305

pkg/parser/php/laravel/blade.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ func (ba *BladeAnalyzer) analyzeFile(filePath string) (BladeTemplate, error) {
6161
}
6262

6363
scanner := bufio.NewScanner(f)
64+
scanner.Buffer(make([]byte, 64*1024), 1024*1024) // Allow lines up to 1MB
6465
lineNum := 0
6566
for scanner.Scan() {
6667
lineNum++

pkg/parser/php/laravel/enricher.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ func (e *Enricher) Enrich(ca *php.CodeAnalyzer, packages []*php.PackageInfo, pat
123123
}
124124
}
125125

126-
logger.Instance.Debug("[LARAVEL] Enrich: %d chunks before blade analysis", len(chunks))
126+
logger.Instance.Debug("[LARAVEL] Enrich: %d chunks after routes, before blade analysis", len(chunks))
127127

128128
// Analyze Blade Templates
129129
bladeFiles := e.adapter.findBladeFiles(paths)

pkg/parser/php/laravel/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,12 @@ type Middleware struct {
134134
type BladeTemplate struct {
135135
Name string `json:"name"` // dot notation: layouts.app
136136
FilePath string `json:"file_path"`
137+
TotalLines int `json:"total_lines"` // total line count of the file
137138
Extends string `json:"extends,omitempty"` // @extends('...')
138139
Sections []BladeSection `json:"sections,omitempty"`
139140
Includes []BladeInclude `json:"includes,omitempty"`
140141
Stacks []string `json:"stacks,omitempty"` // @push/@stack names
141142
Props []string `json:"props,omitempty"` // @props([...])
142-
TotalLines int `json:"total_lines"` // total line count of the file
143143
}
144144

145145
// BladeSection represents a @section or @yield directive

pkg/parser/php/wordpress/analyzer.go

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func (a *Analyzer) AnalyzePaths(paths []string) ([]php.CodeChunk, error) {
8080
// analyzeWordPress performs complete WordPress analysis using both package info and AST
8181
func (a *Analyzer) analyzeWordPress(packages []*php.PackageInfo, paths []string) *WordPressInfo {
8282
info := &WordPressInfo{}
83+
var wcAPICalls []woocommerce.WCAPICall
8384

8485
// Analyze from parsed package info (method calls)
8586
info.Hooks = a.hookAnalyzer.AnalyzeHooks(packages)
@@ -149,6 +150,12 @@ func (a *Analyzer) analyzeWordPress(packages []*php.PackageInfo, paths []string)
149150
}
150151
}
151152

153+
// WooCommerce API calls from AST
154+
wcInfo := a.woocommerceAnalyzer.Analyze(rootNode, path)
155+
if wcInfo != nil && len(wcInfo.APICalls) > 0 {
156+
wcAPICalls = append(wcAPICalls, wcInfo.APICalls...)
157+
}
158+
152159
return nil
153160
})
154161
}
@@ -173,8 +180,11 @@ func (a *Analyzer) analyzeWordPress(packages []*php.PackageInfo, paths []string)
173180
})
174181
}
175182
wcHooks := a.woocommerceAnalyzer.AnalyzeHooksFromWP(wcInputHooks)
176-
if len(wcHooks) > 0 {
177-
wcInfo := &woocommerce.WooCommerceInfo{Hooks: wcHooks}
183+
if len(wcHooks) > 0 || len(wcAPICalls) > 0 {
184+
wcInfo := &woocommerce.WooCommerceInfo{
185+
Hooks: wcHooks,
186+
APICalls: wcAPICalls,
187+
}
178188
info.WooCommerceInfo = wcInfo
179189
}
180190

@@ -379,14 +389,18 @@ func (a *Analyzer) convertToChunks(info *WordPressInfo) []php.CodeChunk {
379389
if info.OxygenInfo != nil {
380390
if oxyInfo, ok := info.OxygenInfo.(*oxygen.OxygenInfo); ok {
381391
for _, elem := range oxyInfo.Elements {
392+
baseClass := elem.BaseClass
393+
if baseClass == "" {
394+
baseClass = "OxyEl"
395+
}
382396
chunks = append(chunks, php.CodeChunk{
383397
Name: elem.ClassName,
384398
Type: "oxy_element",
385399
Language: "php",
386400
FilePath: elem.FilePath,
387401
StartLine: elem.StartLine,
388402
EndLine: elem.EndLine,
389-
Signature: fmt.Sprintf("class %s extends OxyEl", elem.ClassName),
403+
Signature: fmt.Sprintf("class %s extends %s", elem.ClassName, baseClass),
390404
Docstring: fmt.Sprintf("Oxygen Builder Element: %s (methods: %s)", elem.ClassName, strings.Join(elem.Methods, ", ")),
391405
Metadata: map[string]any{
392406
"framework": "wordpress",
@@ -428,7 +442,7 @@ func (a *Analyzer) convertToChunks(info *WordPressInfo) []php.CodeChunk {
428442
FilePath: wcHook.FilePath,
429443
StartLine: wcHook.StartLine,
430444
EndLine: wcHook.EndLine,
431-
Signature: fmt.Sprintf("%s('%s', '%s')", wcHook.HookType, wcHook.HookName, wcHook.Callback),
445+
Signature: buildWCHookSignature(wcHook),
432446
Docstring: fmt.Sprintf("WooCommerce %s hook (%s area): %s", wcHook.HookType, wcHook.Area, wcHook.HookName),
433447
Metadata: map[string]any{
434448
"framework": "wordpress",
@@ -504,6 +518,37 @@ func buildHookSignature(hook WPHook) string {
504518
}
505519
}
506520

521+
// buildWCHookSignature creates a readable signature for a WooCommerce hook
522+
// using the real WordPress function names instead of raw hook type values
523+
func buildWCHookSignature(wcHook woocommerce.WCHook) string {
524+
switch wcHook.HookType {
525+
case "action":
526+
if wcHook.Priority > 0 {
527+
return fmt.Sprintf("add_action('%s', '%s', %d)", wcHook.HookName, wcHook.Callback, wcHook.Priority)
528+
}
529+
return fmt.Sprintf("add_action('%s', '%s')", wcHook.HookName, wcHook.Callback)
530+
case "filter":
531+
if wcHook.Priority > 0 {
532+
return fmt.Sprintf("add_filter('%s', '%s', %d)", wcHook.HookName, wcHook.Callback, wcHook.Priority)
533+
}
534+
return fmt.Sprintf("add_filter('%s', '%s')", wcHook.HookName, wcHook.Callback)
535+
case "action_trigger":
536+
return fmt.Sprintf("do_action('%s')", wcHook.HookName)
537+
case "filter_trigger":
538+
return fmt.Sprintf("apply_filters('%s')", wcHook.HookName)
539+
case "action_removal":
540+
return fmt.Sprintf("remove_action('%s', '%s')", wcHook.HookName, wcHook.Callback)
541+
case "filter_removal":
542+
return fmt.Sprintf("remove_filter('%s', '%s')", wcHook.HookName, wcHook.Callback)
543+
case "action_check":
544+
return fmt.Sprintf("has_action('%s')", wcHook.HookName)
545+
case "filter_check":
546+
return fmt.Sprintf("has_filter('%s')", wcHook.HookName)
547+
default:
548+
return fmt.Sprintf("%s('%s', '%s')", wcHook.HookType, wcHook.HookName, wcHook.Callback)
549+
}
550+
}
551+
507552
// IsWordPressProject detects if the given paths contain a WordPress project.
508553
// It first checks the paths directly (directory-level indicators, plugin headers),
509554
// then walks UP parent directories to find WordPress root indicators.

pkg/parser/php/wordpress/oxygen/analyzer.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ func (a *Analyzer) extractOxygenElement(class php.ClassInfo) OxygenElement {
107107
ClassName: class.Name,
108108
Namespace: class.Namespace,
109109
FullName: class.FullName,
110+
BaseClass: extractBaseClassName(class.Extends),
110111
FilePath: class.FilePath,
111112
StartLine: class.StartLine,
112113
EndLine: class.EndLine,
@@ -177,6 +178,18 @@ func (a *Analyzer) walkForOxygenTemplates(node ast.Vertex, filePath string, info
177178
}
178179
}
179180

181+
// extractBaseClassName extracts the short base class name from a possibly namespaced extends value
182+
func extractBaseClassName(extends string) string {
183+
if extends == "" {
184+
return ""
185+
}
186+
// Get last segment after backslash (e.g., "Ns\OxyEl" → "OxyEl")
187+
if idx := strings.LastIndex(extends, "\\"); idx >= 0 {
188+
return extends[idx+1:]
189+
}
190+
return extends
191+
}
192+
180193
// extractFuncName extracts function name from AST node
181194
func extractFuncName(node ast.Vertex) string {
182195
if node == nil {

pkg/parser/php/wordpress/oxygen/types.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ type OxygenElement struct {
1212
ClassName string `json:"class_name"`
1313
Namespace string `json:"namespace,omitempty"`
1414
FullName string `json:"full_name"`
15-
SlugMethod bool `json:"has_slug"` // Has slug() method
16-
Methods []string `json:"methods,omitempty"` // Detected methods (init, name, slug, icon, controls, render)
15+
BaseClass string `json:"base_class,omitempty"` // OxyEl, OxyElShadow, OxygenElement, etc.
16+
SlugMethod bool `json:"has_slug"` // Has slug() method
17+
Methods []string `json:"methods,omitempty"` // Detected methods (init, name, slug, icon, controls, render)
1718
FilePath string `json:"file_path"`
1819
StartLine int `json:"start_line"`
1920
EndLine int `json:"end_line"`

pkg/parser/php/wordpress/woocommerce/analyzer.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,14 @@ func extractFuncName(node ast.Vertex) string {
287287
}
288288
}
289289
return strings.Join(parts, "\\")
290+
case *ast.NameFullyQualified:
291+
var parts []string
292+
for _, part := range n.Parts {
293+
if namePart, ok := part.(*ast.NamePart); ok {
294+
parts = append(parts, string(namePart.Value))
295+
}
296+
}
297+
return strings.Join(parts, "\\")
290298
}
291299
return ""
292300
}
@@ -333,6 +341,8 @@ func extractExprValue(expr ast.Vertex) string {
333341
return val
334342
case *ast.ScalarLnumber:
335343
return string(n.Value)
344+
case *ast.ScalarDnumber:
345+
return string(n.Value)
336346
case *ast.Name:
337347
var parts []string
338348
for _, part := range n.Parts {
@@ -341,6 +351,14 @@ func extractExprValue(expr ast.Vertex) string {
341351
}
342352
}
343353
return strings.Join(parts, "\\")
354+
case *ast.ExprConstFetch:
355+
return extractExprValue(n.Const)
356+
case *ast.ExprClassConstFetch:
357+
if constName, ok := n.Const.(*ast.Identifier); ok {
358+
if string(constName.Value) == "class" {
359+
return extractExprValue(n.Class) + "::class"
360+
}
361+
}
344362
case *ast.ExprVariable:
345363
if nameNode, ok := n.Name.(*ast.Identifier); ok {
346364
name := string(nameNode.Value)

0 commit comments

Comments
 (0)