package loader
import "fmt"
func BuildDependencyGraph(mods map[string]*ModuleInfo) (map[string][]string, error) {
graph := map[string][]string{}
for name, info := range mods {
graph[name] = info.Imports
for _, dep := range info.Imports {
if _, ok := mods[dep]; !ok {
return nil, fmt.Errorf("module %q imports unknown module %q", name, dep)
}
}
}
return graph, nil
}
type VisitedStatusKind int
const (
VisitedStatusUnseen VisitedStatusKind = iota
VisitedStatusVisiting
VisitedStatusDone
)
func TopoSort(graph map[string][]string) ([]string, error) {
visited := map[string]VisitedStatusKind{}
order := []string{}
var visit func(string) error
visit = func(n string) error {
switch visited[n] {
case VisitedStatusVisiting:
return fmt.Errorf("circular import detected at %q", n)
case VisitedStatusDone:
return nil
}
visited[n] = VisitedStatusVisiting
for _, dep := range graph[n] {
if err := visit(dep); err != nil {
return err
}
}
visited[n] = VisitedStatusDone
order = append(order, n)
return nil
}
for node := range graph {
if visited[node] == VisitedStatusUnseen {
if err := visit(node); err != nil {
return nil, err
}
}
}
return order, nil
}