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  }