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

184 lines
4.5 KiB
Go

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
}