github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/view/parse.go (about) 1 package view 2 3 import "reflect" 4 5 type Element interface{} 6 7 type Prop struct { 8 Type string 9 Value reflect.Value 10 } 11 12 type Node struct { 13 Name string 14 Type string 15 Value reflect.Value 16 Slice bool 17 18 Props map[string]*Prop 19 Children []*Node 20 } 21 22 func parse(name string, v reflect.Value) (*Node, error) { 23 for v.Kind() == reflect.Ptr { 24 v = v.Elem() 25 } 26 27 if v.Kind() != reflect.Struct && v.Kind() != reflect.Slice { 28 panic("ViewModel should be a struct or slice.") 29 } 30 31 t := v.Type() 32 33 node := &Node{ 34 Name: name, 35 Type: t.Name(), 36 Slice: v.Kind() == reflect.Slice, 37 Value: v, 38 } 39 40 if node.Type == "" { 41 node.Type = node.Name 42 } 43 44 if v.Kind() == reflect.Slice { 45 for i := 0; i < v.Len(); i++ { 46 f := v.Index(i) 47 child, err := parse("", f) 48 if err != nil { 49 return nil, err 50 } 51 node.Children = append(node.Children, child) 52 } 53 return node, nil 54 } 55 56 for i := 0; i < v.NumField(); i++ { 57 f := v.Field(i) 58 if f.Kind() == reflect.Struct || f.Kind() == reflect.Slice { 59 child, err := parse(t.Field(i).Name, f) 60 if err != nil { 61 return nil, err 62 } 63 node.Children = append(node.Children, child) 64 } else { 65 if node.Props == nil { 66 node.Props = make(map[string]*Prop) 67 } 68 69 name := t.Field(i).Name 70 node.Props[name] = &Prop{ 71 Type: f.Type().Name(), 72 Value: f, 73 } 74 } 75 } 76 77 return node, nil 78 } 79 80 func (n *Node) prop(name string) (*Prop, bool) { 81 if n.Props == nil { 82 return nil, false 83 } 84 prop, ok := n.Props[name] 85 return prop, ok 86 } 87 88 func (n *Node) Str(name string) (string, bool) { 89 v, ok := n.prop(name) 90 if !ok { 91 return "", false 92 } 93 return v.Value.String(), true 94 } 95 96 func (n *Node) Bool(name string) (bool, bool) { 97 v, ok := n.prop(name) 98 if !ok { 99 return false, false 100 } 101 return v.Value.Bool(), true 102 } 103 104 func Parse(name string, v interface{}) (*Node, error) { 105 return parse(name, reflect.ValueOf(v)) 106 }