Files
fn_registry/registry/indexer.go
T
egutierrez 2d87d6affc feat: indexer con validacion en dos pasadas y CLI con output de errores
Reescribe el indexer con estrategia de dos pasadas:
1. Parsea todos los .md y construye sets de IDs conocidos
2. Valida integridad contra IDs conocidos, inserta solo los validos

El CLI ahora muestra INVALID para errores de validacion y ERROR
para errores de insercion, separando claramente ambos.
Añade test de integracion que verifica que entradas invalidas
se rechazan sin afectar a las validas.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 02:13:44 +01:00

102 lines
2.6 KiB
Go

package registry
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// IndexResult holds stats from an indexing run.
type IndexResult struct {
Functions int
Types int
ValidationErrors []string
Errors []string
}
// Index walks the registry root, parses all .md files, validates integrity,
// and populates the database. It uses two passes:
// 1. Parse all entries and collect known IDs
// 2. Validate references against known IDs, then insert valid entries
func Index(db *DB, root string) (*IndexResult, error) {
if err := db.Purge(); err != nil {
return nil, fmt.Errorf("purging database: %w", err)
}
result := &IndexResult{}
// Pass 1: parse everything
var functions []*Function
var types []*Type
functionsDir := filepath.Join(root, "functions")
if _, err := os.Stat(functionsDir); err == nil {
filepath.Walk(functionsDir, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() || !strings.HasSuffix(path, ".md") {
return nil
}
f, err := ParseFunctionMD(path)
if err != nil {
result.Errors = append(result.Errors, fmt.Sprintf("parse %s: %v", path, err))
return nil
}
functions = append(functions, f)
return nil
})
}
typesDir := filepath.Join(root, "types")
if _, err := os.Stat(typesDir); err == nil {
filepath.Walk(typesDir, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() || !strings.HasSuffix(path, ".md") {
return nil
}
t, err := ParseTypeMD(path)
if err != nil {
result.Errors = append(result.Errors, fmt.Sprintf("parse %s: %v", path, err))
return nil
}
types = append(types, t)
return nil
})
}
// Build known ID sets
knownFunctions := make(map[string]bool, len(functions))
for _, f := range functions {
knownFunctions[f.ID] = true
}
knownTypes := make(map[string]bool, len(types))
for _, t := range types {
knownTypes[t.ID] = true
}
// Pass 2: validate and insert
for _, t := range types {
if verr := ValidateType(t, knownTypes); verr != nil {
result.ValidationErrors = append(result.ValidationErrors, verr.Error())
continue
}
if err := db.InsertType(t); err != nil {
result.Errors = append(result.Errors, fmt.Sprintf("insert %s: %v", t.ID, err))
continue
}
result.Types++
}
for _, f := range functions {
if verr := ValidateFunction(f, knownFunctions, knownTypes); verr != nil {
result.ValidationErrors = append(result.ValidationErrors, verr.Error())
continue
}
if err := db.InsertFunction(f); err != nil {
result.Errors = append(result.Errors, fmt.Sprintf("insert %s: %v", f.ID, err))
continue
}
result.Functions++
}
return result, nil
}