Add GSP links field and link inspection

This commit is contained in:
2026-05-07 10:41:38 +08:00
parent 0c5254eb1b
commit 27e71d8c51
18 changed files with 448 additions and 17 deletions

View File

@@ -3,6 +3,7 @@ package gsp
import (
"encoding/json"
"fmt"
"path/filepath"
"sort"
"strings"
)
@@ -41,6 +42,22 @@ func (p *Project) Validate(stage string) Report {
report.addError("missing_with", unit.ID, unit.File, fmt.Sprintf("with references missing GSP %q", rel.ID))
}
}
for _, link := range unit.Links {
role := strings.TrimSpace(link.Role)
if role != "" && !allowedLinkRoles[role] {
report.addError("invalid_link_role", unit.ID, unit.File, fmt.Sprintf("link role %q is not allowed", role))
}
resolved := p.resolveLink(unit, link)
switch resolved.Status {
case "missing":
report.addWarning("missing_link", unit.ID, unit.File, fmt.Sprintf("link %q does not exist", resolved.Path))
case "invalid":
report.addError("invalid_link", unit.ID, unit.File, fmt.Sprintf("link %q is invalid", resolved.Path))
}
if filepath.IsAbs(resolved.Path) {
report.addWarning("absolute_link_path", unit.ID, unit.File, fmt.Sprintf("link %q is absolute and reduces portability", resolved.Path))
}
}
if unit.Refines != "" {
if _, ok := p.ByID[unit.Refines]; !ok {
report.addError("missing_refines", unit.ID, unit.File, fmt.Sprintf("refines references missing GSP %q", unit.Refines))
@@ -80,7 +97,12 @@ func (p *Project) Index() []IndexEntry {
for _, rel := range unit.With {
with = append(with, rel.ID)
}
links := make([]string, 0, len(unit.Links))
for _, link := range unit.Links {
links = append(links, link.Path)
}
sort.Strings(with)
sort.Strings(links)
entries = append(entries, IndexEntry{
ID: unit.ID,
Title: unit.Title,
@@ -89,6 +111,7 @@ func (p *Project) Index() []IndexEntry {
Resolution: unit.Resolution,
With: with,
Refines: unit.Refines,
Links: links,
})
}
sort.Slice(entries, func(i, j int) bool {
@@ -184,6 +207,7 @@ func (p *Project) PackFor(id, intent, stage string, depth, budget int, filter Fi
units = candidate
approx = len(data)
}
links := p.resolveLinks(units)
return PackResult{
Entry: id,
Intent: intent,
@@ -192,17 +216,19 @@ func (p *Project) PackFor(id, intent, stage string, depth, budget int, filter Fi
Budget: budget,
Truncated: truncated,
Units: units,
Summary: summarizeUnits(units, len(flattened.Warnings)),
Links: links,
Summary: summarizeUnits(units, len(flattened.Warnings), len(links)),
ApproxChars: approx,
Warnings: flattened.Warnings,
}
}
func summarizeUnits(units []*Unit, missingCount int) Summary {
func summarizeUnits(units []*Unit, missingCount, linkCount int) Summary {
summary := Summary{
UnitCount: len(units),
TypeCounts: map[string]int{},
MissingCount: missingCount,
LinkCount: linkCount,
}
min := 99
max := -1