@@ -2,18 +2,17 @@ package meta
22
33import (
44 "bytes"
5- "fmt"
65 "io"
76 "net/url"
87 "os"
98 "reflect"
109 "strconv"
10+ "strings"
1111 "time"
1212
1313 // Packages
1414 server "github.com/mutablelogic/go-server"
1515 httpresponse "github.com/mutablelogic/go-server/pkg/httpresponse"
16- ast "github.com/mutablelogic/go-server/pkg/parser/ast"
1716 types "github.com/mutablelogic/go-server/pkg/types"
1817)
1918
@@ -27,8 +26,16 @@ type Meta struct {
2726 Type reflect.Type
2827 Index []int
2928 Fields []* Meta
29+
30+ // Private fields
31+ label []string
32+ parent * Meta
3033}
3134
35+ const (
36+ labelSeparator = "."
37+ )
38+
3239////////////////////////////////////////////////////////////////////////////////
3340// LIFECYCLE
3441
@@ -46,6 +53,7 @@ func New(v server.Plugin) (*Meta, error) {
4653 return nil , httpresponse .ErrInternalError .Withf ("expected struct, got %T" , v )
4754 } else {
4855 meta .Name = v .Name ()
56+ meta .label = []string {}
4957 meta .Description = v .Description ()
5058 meta .Type = rt
5159 }
@@ -54,7 +62,7 @@ func New(v server.Plugin) (*Meta, error) {
5462 fields := reflect .VisibleFields (rt )
5563 meta .Fields = make ([]* Meta , 0 , len (fields ))
5664 for _ , field := range fields {
57- if field , err := newMetaField (field ); err != nil {
65+ if field , err := newMetaField (field , meta ); err != nil {
5866 return nil , httpresponse .ErrInternalError .With (err .Error ())
5967 } else if field != nil {
6068 meta .Fields = append (meta .Fields , field )
@@ -65,6 +73,26 @@ func New(v server.Plugin) (*Meta, error) {
6573 return meta , nil
6674}
6775
76+ // Return a new metadata object, with a label
77+ func (m * Meta ) WithLabel (label string ) * Meta {
78+ // Copy object
79+ meta := new (Meta )
80+ meta .Name = m .Name
81+ meta .Description = m .Description
82+ meta .Default = m .Default
83+ meta .Type = m .Type
84+ meta .Index = m .Index
85+ meta .Fields = m .Fields
86+
87+ // Make a copy of the label
88+ meta .label = make ([]string , len (m .label ))
89+ copy (meta .label , m .label )
90+ meta .label = append (meta .label , label )
91+
92+ // Return copy of meta
93+ return meta
94+ }
95+
6896////////////////////////////////////////////////////////////////////////////////
6997// STRINGIFY
7098
@@ -78,48 +106,57 @@ func (m *Meta) String() string {
78106
79107func (m * Meta ) Write (w io.Writer ) error {
80108 var buf bytes.Buffer
109+ m .writeBlock (& buf , 2 )
110+ _ , err := w .Write (buf .Bytes ())
111+ return err
112+ }
81113
114+ func (m * Meta ) writeBlock (buf * bytes.Buffer , indent int ) {
115+ prefix := strings .Repeat (" " , indent )
82116 if m .Description != "" {
83- buf .WriteString ("// " )
84- buf .WriteString (m .Description )
85- buf .WriteString ("\n " )
117+ buf .WriteString (prefix + "// " + m .Description + "\n " )
86118 }
87- buf .WriteString (m .Name )
88- buf .WriteString (" \" label\" {\n " )
89-
119+ buf .WriteString (prefix + m .Name )
120+ if label := m .Label (); label != "" {
121+ buf .WriteString (" " + strconv .Quote (label ))
122+ }
123+ buf .WriteString (" {\n " )
90124 for _ , field := range m .Fields {
91- buf .WriteString (" " )
92- buf .WriteString (field .Name )
93- buf .WriteString (" = " )
94- buf .WriteString ("<" + typeName (field .Type ) + ">" )
125+ // Block
126+ if field .Type == nil {
127+ buf .WriteString ("\n " )
128+ field .writeBlock (buf , indent + 2 )
129+ continue
130+ }
95131
132+ // Field
133+ buf .WriteString (prefix + prefix + field .Name + " = " + "<" + typeName (field .Type ) + ">" )
96134 if field .Description != "" {
97- buf .WriteString (" // " )
98- buf .WriteString (field .Description )
135+ buf .WriteString (" // " + field .Description )
99136 }
137+ buf .WriteString (prefix + "// " + m .Label () + "\n " )
100138 if field .Default != "" {
101139 buf .WriteString (" (default: " + types .Quote (field .Default ) + ")" )
102140 }
103-
104141 buf .WriteString ("\n " )
105142 }
106-
107- buf .WriteString ("}\n " )
108- _ , err := w .Write (buf .Bytes ())
109- return err
143+ buf .WriteString (prefix + "}\n " )
110144}
111145
112146////////////////////////////////////////////////////////////////////////////////
113147// PUBLIC METHODS
114148
115- func (m * Meta ) Validate (values any ) error {
116- dict := values .(map [string ]ast.Node )
117- for _ , field := range m .Fields {
118- fmt .Println (field .Name , "=>" , dict [field .Name ])
149+ // Return the label
150+ func (m * Meta ) Label () string {
151+ var parts []string
152+ for meta := m ; meta != nil ; meta = meta .parent {
153+ parts = append (parts , meta .label ... )
119154 }
120- return nil
155+ return strings . Join ( parts , labelSeparator )
121156}
122157
158+ // Create a new plugin instance and set default values, then validate any
159+ // required fields
123160func (m * Meta ) New () server.Plugin {
124161 obj := reflect .New (m .Type )
125162 for _ , field := range m .Fields {
@@ -129,10 +166,25 @@ func (m *Meta) New() server.Plugin {
129166 return obj .Interface ().(server.Plugin )
130167}
131168
169+ // Get a metadata field by name
170+ func (m * Meta ) Get (label string ) * Meta {
171+ for _ , field := range m .Fields {
172+ if field .Label () == label {
173+ return field
174+ }
175+ if field .Type == nil {
176+ if field := field .Get (label ); field != nil {
177+ return field
178+ }
179+ }
180+ }
181+ return nil
182+ }
183+
132184////////////////////////////////////////////////////////////////////////////////
133185// PRIVATE METHODS
134186
135- func newMetaField (rf reflect.StructField ) (* Meta , error ) {
187+ func newMetaField (rf reflect.StructField , parent * Meta ) (* Meta , error ) {
136188 meta := new (Meta )
137189 meta .Index = rf .Index
138190
@@ -142,14 +194,31 @@ func newMetaField(rf reflect.StructField) (*Meta, error) {
142194 return nil , nil
143195 } else {
144196 meta .Name = name
197+ meta .label = []string {name }
198+ meta .parent = parent
145199 }
146200
147201 // Description
148- if description , _ := valueForField (rf , "description" , "help" ); description != "" {
202+ if description , _ := valueForField (rf , "description" , "desc" , " help" ); description != "" {
149203 meta .Description = description
150204 }
151205
152- // Env - needs to be an identififer
206+ // Block type
207+ if rf .Type .Kind () == reflect .Struct && rf .Type != timeType {
208+ // Get visible fields
209+ fields := reflect .VisibleFields (rf .Type )
210+ meta .Fields = make ([]* Meta , 0 , len (fields ))
211+ for _ , field := range fields {
212+ if field , err := newMetaField (field , meta ); err != nil {
213+ return nil , httpresponse .ErrInternalError .With (err .Error ())
214+ } else if field != nil {
215+ meta .Fields = append (meta .Fields , field )
216+ }
217+ }
218+ return meta , nil
219+ }
220+
221+ // Set default for the field
153222 if env , _ := valueForField (rf , "env" ); types .IsIdentifier (env ) {
154223 meta .Default = "${" + env + "}"
155224 } else if def , _ := valueForField (rf , "default" ); def != "" {
@@ -158,7 +227,7 @@ func newMetaField(rf reflect.StructField) (*Meta, error) {
158227
159228 // Type
160229 if t := typeName (rf .Type ); t == "" {
161- return nil , httpresponse .ErrInternalError .Withf ("unsupported type: %s " , rf .Type )
230+ return nil , httpresponse .ErrInternalError .Withf ("unsupported type: %v " , rf .Type )
162231 } else {
163232 meta .Type = rf .Type
164233 }
@@ -228,7 +297,7 @@ func setValue(rv reflect.Value, str string) error {
228297 }
229298 fallthrough
230299 default :
231- // TODO: Datetime
300+ // TODO: time.Time
232301 return httpresponse .ErrBadRequest .Withf ("invalid value for %s: %q" , rv .Type (), str )
233302 }
234303
0 commit comments