ADR 0593 §7: the composer with its refusals leaves mesh-sdk, so mesh-sdk carries no composition rule. The catalogue functions only the node-engine's composition reaches (Resolve, Resolution's Compose, Declaration, DataItems, LeftOut, Rules and the rest, the settings, placeholder and template refusals, the rendering helpers) are copied with their tests into internal/compose/resolution; a method of a mesh-sdk shape becomes a function taking it first. The composition calls its own copies, and the captured catalogue its tests read lives here now, shared by mesh-compose's tests. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
90 lines
2.4 KiB
Go
90 lines
2.4 KiB
Go
package resolution
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
|
|
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// requirementsContributedTo is every requirement m contributes to, sorted.
|
|
func requirementsContributedTo(m mcat.Manifest) []string {
|
|
seen := map[string]bool{}
|
|
for to := range m.Contributes {
|
|
seen[to] = true
|
|
}
|
|
for to := range m.ContributesMany {
|
|
seen[to] = true
|
|
}
|
|
out := make([]string, 0, len(seen))
|
|
for to := range seen {
|
|
out = append(out, to)
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|
|
|
|
// ServedOwnNames fills the provider's own composed names into what it serves one provision's
|
|
// consumers, from this resolution's composition of the provider's machine (ADR 0346).
|
|
//
|
|
// A value naming a name this machine does not compose is left out, with its key, and said. The map is
|
|
// copied only when something changes, as ServedTo does: the caller's may be the manifest's.
|
|
func ServedOwnNames(r mcat.Resolution, m mcat.Manifest, provision string, serves map[string]any, layers []mcat.Layer) (
|
|
map[string]any, []string, error) {
|
|
var asking []string
|
|
for _, key := range sortedAnyKeys(serves) {
|
|
if text, ok := serves[key].(string); ok && bound.MatchString(text) {
|
|
asking = append(asking, key)
|
|
}
|
|
}
|
|
if len(asking) == 0 {
|
|
return serves, nil, nil
|
|
}
|
|
own := map[string]map[string]string{}
|
|
for _, to := range requirementsContributedTo(m) {
|
|
names, err := resolutionOwnNames(r, m, to, layers)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
values := map[string]string{}
|
|
withOwnNames(values, names)
|
|
own[to] = values
|
|
}
|
|
out := make(map[string]any, len(serves))
|
|
for k, v := range serves {
|
|
out[k] = v
|
|
}
|
|
var said []string
|
|
for _, key := range asking {
|
|
text := serves[key].(string)
|
|
var missing string
|
|
filled := bound.ReplaceAllStringFunc(text, func(token string) string {
|
|
parts := bound.FindStringSubmatch(token)
|
|
if value := own[parts[1]][parts[2]]; value != "" && parts[3] == "" {
|
|
return value
|
|
}
|
|
if missing == "" {
|
|
missing = token
|
|
}
|
|
return token
|
|
})
|
|
if missing != "" {
|
|
delete(out, key)
|
|
said = append(said, fmt.Sprintf(
|
|
"%s serves %s without %q: it names %s, and %s composes no such name for %s (it has no "+
|
|
"public domain, or the endpoint is not reached publicly) (novox/hq ADR 0346)",
|
|
m.Module, provision, key, missing, orHere(r.Node), m.Module))
|
|
continue
|
|
}
|
|
out[key] = filled
|
|
}
|
|
return out, said, nil
|
|
}
|
|
|
|
func orHere(node string) string {
|
|
if node == "" {
|
|
return "this machine"
|
|
}
|
|
return node
|
|
}
|