Files
GSP/toolkit/internal/gsp/load.go

125 lines
3.2 KiB
Go
Raw Normal View History

2026-05-06 18:40:37 +08:00
package gsp
import (
"os"
"path/filepath"
"sort"
"strings"
"gopkg.in/yaml.v3"
)
var ignoredDirs = map[string]bool{
".git": true,
".gsp": true,
"node_modules": true,
"dist": true,
"build": true,
"bin": true,
}
func LoadProject(root string) (*Project, error) {
absRoot, err := filepath.Abs(root)
if err != nil {
return nil, err
}
project := &Project{
Root: absRoot,
ByID: map[string]*Unit{},
Duplicates: map[string][]*Unit{},
}
manifest, err := loadManifest(absRoot)
if err != nil {
project.LoadIssues = append(project.LoadIssues, Issue{Level: "error", Code: "manifest_error", File: "gsp.manifest", Message: err.Error()})
}
project.Manifest = manifest
2026-05-07 11:04:11 +08:00
fields, err := loadFieldRegistry(absRoot, project.Manifest)
if err != nil {
project.LoadIssues = append(project.LoadIssues, Issue{Level: "error", Code: "field_registry_error", File: project.Manifest.fieldRegistryPath(), Message: err.Error()})
}
project.Fields = fields
2026-05-06 18:40:37 +08:00
var files []string
for _, scanEntry := range project.Manifest.scanEntries() {
scanPath := filepath.Join(absRoot, filepath.FromSlash(scanEntry))
info, statErr := os.Stat(scanPath)
if statErr != nil {
project.LoadIssues = append(project.LoadIssues, Issue{Level: "warning", Code: "scan_missing", File: scanEntry, Message: "scan path does not exist"})
continue
2026-05-06 18:40:37 +08:00
}
if !info.IsDir() {
if strings.EqualFold(filepath.Ext(scanPath), ".gsp") {
files = append(files, scanPath)
2026-05-06 18:40:37 +08:00
}
continue
2026-05-06 18:40:37 +08:00
}
walkErr := filepath.WalkDir(scanPath, func(path string, entry os.DirEntry, walkErr error) error {
if walkErr != nil {
project.LoadIssues = append(project.LoadIssues, Issue{Level: "error", Code: "walk_error", File: path, Message: walkErr.Error()})
return nil
}
if entry.IsDir() {
if ignoredDirs[entry.Name()] {
return filepath.SkipDir
}
return nil
}
if strings.EqualFold(filepath.Ext(entry.Name()), ".gsp") {
files = append(files, path)
}
return nil
})
if walkErr != nil {
return nil, walkErr
2026-05-06 18:40:37 +08:00
}
}
sort.Strings(files)
for _, file := range files {
unit, err := readUnit(absRoot, file)
if err != nil {
project.LoadIssues = append(project.LoadIssues, Issue{Level: "error", Code: "parse_error", File: relPath(absRoot, file), Message: err.Error()})
continue
}
project.Units = append(project.Units, unit)
if unit.ID == "" {
continue
}
if existing, ok := project.ByID[unit.ID]; ok {
project.Duplicates[unit.ID] = append(project.Duplicates[unit.ID], existing, unit)
continue
}
project.ByID[unit.ID] = unit
}
return project, nil
}
func readUnit(root, file string) (*Unit, error) {
data, err := os.ReadFile(file)
if err != nil {
return nil, err
}
var unit Unit
if err := yaml.Unmarshal(data, &unit); err != nil {
return nil, err
}
2026-05-07 11:04:11 +08:00
var raw map[string]any
if err := yaml.Unmarshal(data, &raw); err != nil {
return nil, err
}
unit.RawFields = map[string]any{}
for key, value := range raw {
unit.RawFields[key] = normalizeRawYAML(value)
}
2026-05-06 18:40:37 +08:00
unit.File = relPath(root, file)
return &unit, nil
}
func relPath(root, path string) string {
rel, err := filepath.Rel(root, path)
if err != nil {
return path
}
return filepath.ToSlash(rel)
}