package gsp import ( "fmt" "gopkg.in/yaml.v3" ) var resolutionRank = map[string]int{ "": 0, "L0": 0, "L1": 1, "L2": 2, "L3": 3, "L4": 4, "L5": 5, } type Unit struct { ID string `json:"id" yaml:"id"` Title string `json:"title,omitempty" yaml:"title"` Context string `json:"context,omitempty" yaml:"context"` Resolution string `json:"resolution,omitempty" yaml:"resolution"` With Relations `json:"with,omitempty" yaml:"with"` Refines string `json:"refines,omitempty" yaml:"refines"` Type string `json:"type,omitempty" yaml:"type"` File string `json:"file,omitempty" yaml:"-"` } type Relation struct { ID string `json:"id" yaml:"id"` Context string `json:"context,omitempty" yaml:"context"` } type Relations []Relation func (r *Relations) UnmarshalYAML(value *yaml.Node) error { if value.Kind == 0 || value.Tag == "!!null" { *r = nil return nil } if value.Kind != yaml.SequenceNode { return fmt.Errorf("with must be a list") } out := make([]Relation, 0, len(value.Content)) for _, item := range value.Content { switch item.Kind { case yaml.ScalarNode: if item.Value == "" { return fmt.Errorf("with item cannot be empty") } out = append(out, Relation{ID: item.Value}) case yaml.MappingNode: var rel Relation if err := item.Decode(&rel); err != nil { return err } if rel.ID == "" { return fmt.Errorf("with object item requires id") } out = append(out, rel) default: return fmt.Errorf("with item must be a string or object") } } *r = out return nil } type Issue struct { Level string `json:"level"` Code string `json:"code"` ID string `json:"id,omitempty"` File string `json:"file,omitempty"` Message string `json:"message"` } type Report struct { OK bool `json:"ok"` Errors []Issue `json:"errors,omitempty"` Warnings []Issue `json:"warnings,omitempty"` Notices []Issue `json:"notices,omitempty"` } func (r *Report) addError(code, id, file, message string) { r.Errors = append(r.Errors, Issue{Level: "error", Code: code, ID: id, File: file, Message: message}) r.OK = false } func (r *Report) addWarning(code, id, file, message string) { r.Warnings = append(r.Warnings, Issue{Level: "warning", Code: code, ID: id, File: file, Message: message}) } func (r *Report) addNotice(code, id, file, message string) { r.Notices = append(r.Notices, Issue{Level: "notice", Code: code, ID: id, File: file, Message: message}) } type Project struct { Root string Manifest *Manifest Units []*Unit ByID map[string]*Unit Duplicates map[string][]*Unit LoadIssues []Issue } type IndexEntry struct { ID string `json:"id"` Title string `json:"title,omitempty"` File string `json:"file"` Type string `json:"type,omitempty"` Resolution string `json:"resolution,omitempty"` With []string `json:"with,omitempty"` Refines string `json:"refines,omitempty"` } type FlattenResult struct { Entry string `json:"entry"` Depth int `json:"depth"` Units []*Unit `json:"units"` Warnings []Issue `json:"warnings,omitempty"` } type TraceResult struct { Entry string `json:"entry"` Depth int `json:"depth"` Nodes []*Unit `json:"nodes"` Edges []GraphEdge `json:"edges"` Warnings []Issue `json:"warnings,omitempty"` } type PackResult struct { Entry string `json:"entry"` Depth int `json:"depth"` Budget int `json:"budget,omitempty"` Truncated bool `json:"truncated"` Units []*Unit `json:"units"` ApproxChars int `json:"approxChars"` Warnings []Issue `json:"warnings,omitempty"` } type Graph struct { Nodes []GraphNode `json:"nodes"` Edges []GraphEdge `json:"edges"` } type GraphNode struct { ID string `json:"id"` Title string `json:"title,omitempty"` Type string `json:"type,omitempty"` Resolution string `json:"resolution,omitempty"` File string `json:"file,omitempty"` Missing bool `json:"missing,omitempty"` } type GraphEdge struct { From string `json:"from"` To string `json:"to"` Kind string `json:"kind"` } type Filter struct { IncludeTypes map[string]bool ExcludeTypes map[string]bool } func (f Filter) Allows(unit *Unit) bool { if unit == nil { return false } if len(f.IncludeTypes) > 0 && !f.IncludeTypes[unit.Type] { return false } if len(f.ExcludeTypes) > 0 && f.ExcludeTypes[unit.Type] { return false } return true } func resolutionValue(value string) (int, bool) { rank, ok := resolutionRank[value] return rank, ok }