package cabana import "encoding/json" // FormSchema is the locale-neutral form contract compiled once at boot. // Display strings stay as source keys until a request localizes a copy. type FormSchema struct { Name string `json:"name,omitempty"` ModelClass string `json:"modelClass,omitempty"` Fields []FormField `json:"fields"` } // FormField is one Winter field in source order. JSON keys keep Winter spelling. type FormField struct { Name string `json:"name"` Type string `json:"type"` Label string `json:"label,omitempty"` Comment string `json:"comment,omitempty"` Span string `json:"span,omitempty"` Tab string `json:"tab,omitempty"` Size string `json:"size,omitempty"` Context *fieldContext `json:"context,omitempty"` NameFrom string `json:"nameFrom,omitempty"` EmptyOption string `json:"emptyOption,omitempty"` Relation string `json:"relation,omitempty"` Required bool `json:"required,omitempty"` Default *jsonScalar `json:"default,omitempty"` Attributes map[string]jsonScalar `json:"attributes,omitempty"` Options []FormOption `json:"options,omitempty"` optionsMethod string } // FormOption is one dropdown choice. Value keeps the YAML scalar's JSON type. type FormOption struct { Value jsonScalar `json:"value"` Label string `json:"label"` } // jsonScalar is a JSON scalar that still emits false, 0, and empty string. type jsonScalar struct { raw json.RawMessage } func (s jsonScalar) MarshalJSON() ([]byte, error) { if len(s.raw) == 0 { return []byte("null"), nil } return s.raw, nil } // fieldContext preserves a single Winter context string or a source-ordered list. type fieldContext struct { single bool values []string } func (c fieldContext) MarshalJSON() ([]byte, error) { if c.single { text := "" if len(c.values) > 0 { text = c.values[0] } return json.Marshal(text) } values := c.values if values == nil { values = []string{} } return json.Marshal(values) }