properties.go 2.4 KB

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