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
65 lines
2.2 KiB
Go
65 lines
2.2 KiB
Go
package resolution
|
|
|
|
import (
|
|
"sort"
|
|
|
|
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// meshWords are the settings keys the mesh reads itself; a module declares none of them.
|
|
var meshWords = map[string]bool{mcat.PortsSetting: true, mcat.ExposeSetting: true, mcat.ReachSetting: true, mcat.EndpointsSetting: true, mcat.PlacesSetting: true, mcat.AccessesSetting: true, mcat.NetworksSetting: true}
|
|
|
|
// Defaults is the layer a module's own defaults make, or nothing when it gives none.
|
|
func Defaults(m mcat.Manifest) (mcat.Layer, bool) {
|
|
if len(m.Settings) == 0 {
|
|
return mcat.Layer{}, false
|
|
}
|
|
values := map[string]any{}
|
|
for key, d := range m.Settings {
|
|
if d.Default != nil {
|
|
values[key] = d.Default
|
|
}
|
|
}
|
|
return mcat.Layer{From: mcat.DefaultLayer, Values: values, Default: true}, len(values) > 0
|
|
}
|
|
|
|
// WithDefaults is a module's layers with its defaults under them, for filling `${setting:<key>}`.
|
|
func WithDefaults(m mcat.Manifest, layers []mcat.Layer) []mcat.Layer {
|
|
d, has := Defaults(m)
|
|
if !has {
|
|
return layers
|
|
}
|
|
return append([]mcat.Layer{d}, layers...)
|
|
}
|
|
|
|
// Effective is every key a module gives a default or a layer sets, with its value and where it came
|
|
// from: the default, then the mesh's layer, then the node's — later wins.
|
|
func Effective(m mcat.Manifest, layers []mcat.Layer) []mcat.SettingSource {
|
|
byKey := map[string]*mcat.SettingSource{}
|
|
for key, d := range m.Settings {
|
|
if d.Default == nil {
|
|
// A required config value has no default (ADR 0348 §4); a settings declaration always has one.
|
|
continue
|
|
}
|
|
byKey[key] = &mcat.SettingSource{Key: key, Value: d.Default, From: mcat.DefaultLayer, FromDefault: true,
|
|
Default: d.Default, HasDefault: true}
|
|
}
|
|
for _, layer := range layers {
|
|
// As the layer is said, placement too: `settings` answers it as a person set it.
|
|
for key, v := range layer.Whole() {
|
|
s, ok := byKey[key]
|
|
if !ok {
|
|
s = &mcat.SettingSource{Key: key}
|
|
byKey[key] = s
|
|
}
|
|
s.Value, s.From, s.FromDefault = v, layer.From, layer.Default
|
|
}
|
|
}
|
|
out := make([]mcat.SettingSource, 0, len(byKey))
|
|
for _, s := range byKey {
|
|
out = append(out, *s)
|
|
}
|
|
sort.Slice(out, func(i, j int) bool { return out[i].Key < out[j].Key })
|
|
return out
|
|
}
|