feat(stack): converter docker run→compose (port REA modul 1) — 19 golden vektor + CLI tia-love convert
CI / test (push) Successful in 24s
CI / test (push) Successful in 24s
This commit is contained in:
1 parent
f555f27467
commit
b84afdb494
11 files changed
+1519
-159
No files matched your search
@@ -0,0 +1,127 @@
|
||||
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)
|
||||
}
|
||||
Reference in new issue
Block a user