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{}, } var files []string err = filepath.WalkDir(absRoot, 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 err != nil { return nil, err } 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 } 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) }