github.com/theliebeskind/genfig@v0.1.5-alpha/writers/schema.go (about) 1 package writers 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "sort" 8 "strings" 9 10 "github.com/theliebeskind/genfig/models" 11 u "github.com/theliebeskind/genfig/util" 12 ) 13 14 const ( 15 defaultSchemaRootName = "Config" 16 ) 17 18 //WriteAndReturnSchema writes 19 func WriteAndReturnSchema(w io.Writer, c map[string]interface{}) (s models.SchemaMap, err error) { 20 defer func() { 21 if r := recover(); r != nil { 22 err = u.RecoverError(r) 23 return 24 } 25 }() 26 27 s = models.SchemaMap{} 28 // using NoopWriter since top level is not needed 29 WriteSchema(u.NoopWriter{}, defaultSchemaRootName, c, s, 0) 30 31 buf := bytes.NewBuffer([]byte{}) 32 // write top level schema type definition (usually 'Config') 33 buf.Write(u.B("type " + defaultSchemaRootName + " " + s[defaultSchemaRootName].Content + nl)) 34 keys := []string{} 35 for k := range s { 36 keys = append(keys, k) 37 } 38 sort.Strings(keys) 39 for _, k := range keys { 40 v := s[k] 41 if v.IsStruct { 42 if k == defaultSchemaRootName { 43 continue 44 } 45 buf.Write(u.B("type " + strings.Replace(k, "_", "", -1) + " " + v.Content + nl)) 46 } 47 } 48 49 // now write buffer to writer 50 w.Write(buf.Bytes()) 51 return 52 } 53 54 //WriteSchema writes 55 func WriteSchema(w io.Writer, k string, v interface{}, s models.SchemaMap, l int) bool { 56 if l > maxLevel { 57 panic(fmt.Errorf("Maximum of %d levels exceeded", maxLevel)) 58 } 59 b := bytes.NewBuffer([]byte{}) 60 n := strings.Title(k) 61 isStruct := WriteSchemaType(b, n, v, s, l) 62 63 n = strings.Replace(n, "_", "", -1) 64 s[n] = models.Schema{ 65 IsStruct: isStruct, 66 Content: b.String(), 67 Path: k, 68 } 69 w.Write(b.Bytes()) 70 71 return isStruct 72 } 73 74 // WriteSchemaType the type text to a writer and returns, if type is a struct or not 75 //WriteSchemaType writes 76 func WriteSchemaType(w io.Writer, p string, v interface{}, s models.SchemaMap, l int) (isStruct bool) { 77 switch v.(type) { 78 case map[string]interface{}: 79 isStruct = true 80 buf := bytes.NewBuffer([]byte{}) 81 w.Write(u.B("struct {" + nl)) 82 for _k, _v := range v.(map[string]interface{}) { 83 _k = strings.Title(_k) 84 _isStruct := WriteSchema(buf, p+"_"+_k, _v, s, l+1) 85 if _isStruct { 86 w.Write(u.B(indent + _k + " " + strings.Replace(p, "_", "", -1) + _k + nl)) 87 } else { 88 w.Write(u.B(indent + _k + " " + buf.String() + nl)) 89 } 90 buf.Reset() 91 } 92 // inject _map 93 if l == 0 { 94 w.Write(u.B(indent + "_map map[string]interface{} " + nl)) 95 } 96 w.Write(u.B("}" + nl)) 97 case map[interface{}]interface{}: 98 isStruct = true 99 buf := bytes.NewBuffer([]byte{}) 100 w.Write(u.B("struct {" + nl)) 101 for _k, _v := range v.(map[interface{}]interface{}) { 102 _K := strings.Title(fmt.Sprintf("%v", _k)) 103 _isStruct := WriteSchema(buf, p+"_"+_K, _v, s, l+1) 104 if _isStruct { 105 w.Write(u.B(indent + _K + " " + strings.Replace(p, "_", "", -1) + _K + nl)) 106 } else { 107 w.Write(u.B(indent + _K + " " + buf.String() + nl)) 108 } 109 buf.Reset() 110 } 111 w.Write(u.B("}" + nl)) 112 case []interface{}: 113 w.Write(u.B(u.Make64(u.DetectSliceTypeString(v.([]interface{}))))) 114 default: 115 w.Write(u.B(u.Make64(fmt.Sprintf("%T", v)))) 116 } 117 return 118 }