Files

128 lines
3.1 KiB
Go

package stack
import "gopkg.in/yaml.v3"
// svcBuilder — mapping YAML berurut (urutan key = urutan flag, seperti
// referensi). Semua mutasi lewat helper agar urutan deterministik.
type svcBuilder struct {
root *yaml.Node // MappingNode
}
func newSvc() *svcBuilder {
return &svcBuilder{root: &yaml.Node{Kind: yaml.MappingNode}}
}
func (s *svcBuilder) get(key string) *yaml.Node {
for i := 0; i+1 < len(s.root.Content); i += 2 {
if s.root.Content[i].Value == key {
return s.root.Content[i+1]
}
}
return nil
}
func (s *svcBuilder) has(key string) bool { return s.get(key) != nil }
func (s *svcBuilder) set(key string, v *yaml.Node) {
for i := 0; i+1 < len(s.root.Content); i += 2 {
if s.root.Content[i].Value == key {
s.root.Content[i+1] = v
return
}
}
s.root.Content = append(s.root.Content, strNode(key), v)
}
func (s *svcBuilder) del(key string) {
for i := 0; i+1 < len(s.root.Content); i += 2 {
if s.root.Content[i].Value == key {
s.root.Content = append(s.root.Content[:i], s.root.Content[i+2:]...)
return
}
}
}
// ensureMap — mapping node pada path, dibuat bila belum ada.
func (s *svcBuilder) ensureMap(path ...string) *yaml.Node {
cur := s.root
for _, k := range path {
next := nodeKey(cur, k)
if next == nil {
next = &yaml.Node{Kind: yaml.MappingNode}
appendKV(cur, strNode(k), next)
}
if next.Kind != yaml.MappingNode {
next.Kind = yaml.MappingNode
next.Content = nil
}
cur = next
}
return cur
}
func nodeKey(m *yaml.Node, k string) *yaml.Node {
for i := 0; i+1 < len(m.Content); i += 2 {
if m.Content[i].Value == k {
return m.Content[i+1]
}
}
return nil
}
func appendKV(m *yaml.Node, k, v *yaml.Node) {
m.Content = append(m.Content, k, v)
}
// setPath — set scalar/value pada path (mengganti bila sudah ada).
func (s *svcBuilder) setPath(path []string, v *yaml.Node) {
if len(path) == 0 {
return
}
parent := s.ensureMap(path[:len(path)-1]...)
last := path[len(path)-1]
if old := nodeKey(parent, last); old != nil {
*old = *v
return
}
appendKV(parent, strNode(last), v)
}
// appendAt — tambah item ke sequence pada path (dibuat bila belum ada).
func (s *svcBuilder) appendAt(path []string, item *yaml.Node) {
if len(path) == 0 {
return
}
parent := s.ensureMap(path[:len(path)-1]...)
last := path[len(path)-1]
seq := nodeKey(parent, last)
if seq == nil {
seq = &yaml.Node{Kind: yaml.SequenceNode}
appendKV(parent, strNode(last), seq)
}
if seq.Kind != yaml.SequenceNode {
*seq = yaml.Node{Kind: yaml.SequenceNode}
}
seq.Content = append(seq.Content, item)
}
// mapPairs — set key:value berurutan ke dalam mapping pada path.
func (s *svcBuilder) mapPairs(path []string, pairs [][2]string) {
m := s.ensureMap(path...)
for _, kv := range pairs {
if old := nodeKey(m, kv[0]); old != nil {
*old = *strNode(kv[1])
continue
}
// nilai numerik → int (parity MapArray/Map referensi)
appendKV(m, strNode(kv[0]), scalarAuto(kv[1]))
}
}
// scalarAuto — "2048" → int, selain itu string.
func scalarAuto(v string) *yaml.Node {
if isIntStr(v) {
return intNode(parseInt(v))
}
return strNode(v)
}