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) }