1package spec 2 3import ( 4 "bytes" 5 "encoding/json" 6 "reflect" 7 "sort" 8) 9 10// OrderSchemaItem holds a named schema (e.g. from a property of an object) 11type OrderSchemaItem struct { 12 Name string 13 Schema 14} 15 16// OrderSchemaItems is a sortable slice of named schemas. 17// The ordering is defined by the x-order schema extension. 18type OrderSchemaItems []OrderSchemaItem 19 20// MarshalJSON produces a json object with keys defined by the name schemas 21// of the OrderSchemaItems slice, keeping the original order of the slice. 22func (items OrderSchemaItems) MarshalJSON() ([]byte, error) { 23 buf := bytes.NewBuffer(nil) 24 buf.WriteString("{") 25 for i := range items { 26 if i > 0 { 27 buf.WriteString(",") 28 } 29 buf.WriteString("\"") 30 buf.WriteString(items[i].Name) 31 buf.WriteString("\":") 32 bs, err := json.Marshal(&items[i].Schema) 33 if err != nil { 34 return nil, err 35 } 36 buf.Write(bs) 37 } 38 buf.WriteString("}") 39 return buf.Bytes(), nil 40} 41 42func (items OrderSchemaItems) Len() int { return len(items) } 43func (items OrderSchemaItems) Swap(i, j int) { items[i], items[j] = items[j], items[i] } 44func (items OrderSchemaItems) Less(i, j int) (ret bool) { 45 ii, oki := items[i].Extensions.GetString("x-order") 46 ij, okj := items[j].Extensions.GetString("x-order") 47 if oki { 48 if okj { 49 defer func() { 50 if err := recover(); err != nil { 51 defer func() { 52 if err = recover(); err != nil { 53 ret = items[i].Name < items[j].Name 54 } 55 }() 56 ret = reflect.ValueOf(ii).String() < reflect.ValueOf(ij).String() 57 } 58 }() 59 return reflect.ValueOf(ii).Int() < reflect.ValueOf(ij).Int() 60 } 61 return true 62 } else if okj { 63 return false 64 } 65 return items[i].Name < items[j].Name 66} 67 68// SchemaProperties is a map representing the properties of a Schema object. 69// It knows how to transform its keys into an ordered slice. 70type SchemaProperties map[string]Schema 71 72// ToOrderedSchemaItems transforms the map of properties into a sortable slice 73func (properties SchemaProperties) ToOrderedSchemaItems() OrderSchemaItems { 74 items := make(OrderSchemaItems, 0, len(properties)) 75 for k, v := range properties { 76 items = append(items, OrderSchemaItem{ 77 Name: k, 78 Schema: v, 79 }) 80 } 81 sort.Sort(items) 82 return items 83} 84 85// MarshalJSON produces properties as json, keeping their order. 86func (properties SchemaProperties) MarshalJSON() ([]byte, error) { 87 if properties == nil { 88 return []byte("null"), nil 89 } 90 return json.Marshal(properties.ToOrderedSchemaItems()) 91} 92