utils.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // author xeipuuv
  15. // author-github https://github.com/xeipuuv
  16. // author-mail xeipuuv@gmail.com
  17. //
  18. // repository-name gojsonschema
  19. // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
  20. //
  21. // description Various utility functions.
  22. //
  23. // created 26-02-2013
  24. package gojsonschema
  25. import (
  26. "encoding/json"
  27. "math/big"
  28. "reflect"
  29. )
  30. func isKind(what interface{}, kinds ...reflect.Kind) bool {
  31. target := what
  32. if isJSONNumber(what) {
  33. // JSON Numbers are strings!
  34. target = *mustBeNumber(what)
  35. }
  36. targetKind := reflect.ValueOf(target).Kind()
  37. for _, kind := range kinds {
  38. if targetKind == kind {
  39. return true
  40. }
  41. }
  42. return false
  43. }
  44. func existsMapKey(m map[string]interface{}, k string) bool {
  45. _, ok := m[k]
  46. return ok
  47. }
  48. func isStringInSlice(s []string, what string) bool {
  49. for i := range s {
  50. if s[i] == what {
  51. return true
  52. }
  53. }
  54. return false
  55. }
  56. // indexStringInSlice returns the index of the first instance of 'what' in s or -1 if it is not found in s.
  57. func indexStringInSlice(s []string, what string) int {
  58. for i := range s {
  59. if s[i] == what {
  60. return i
  61. }
  62. }
  63. return -1
  64. }
  65. func marshalToJSONString(value interface{}) (*string, error) {
  66. mBytes, err := json.Marshal(value)
  67. if err != nil {
  68. return nil, err
  69. }
  70. sBytes := string(mBytes)
  71. return &sBytes, nil
  72. }
  73. func marshalWithoutNumber(value interface{}) (*string, error) {
  74. // The JSON is decoded using https://golang.org/pkg/encoding/json/#Decoder.UseNumber
  75. // This means the numbers are internally still represented as strings and therefore 1.00 is unequal to 1
  76. // One way to eliminate these differences is to decode and encode the JSON one more time without Decoder.UseNumber
  77. // so that these differences in representation are removed
  78. jsonString, err := marshalToJSONString(value)
  79. if err != nil {
  80. return nil, err
  81. }
  82. var document interface{}
  83. err = json.Unmarshal([]byte(*jsonString), &document)
  84. if err != nil {
  85. return nil, err
  86. }
  87. return marshalToJSONString(document)
  88. }
  89. func isJSONNumber(what interface{}) bool {
  90. switch what.(type) {
  91. case json.Number:
  92. return true
  93. }
  94. return false
  95. }
  96. func checkJSONInteger(what interface{}) (isInt bool) {
  97. jsonNumber := what.(json.Number)
  98. bigFloat, isValidNumber := new(big.Rat).SetString(string(jsonNumber))
  99. return isValidNumber && bigFloat.IsInt()
  100. }
  101. // same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
  102. const (
  103. maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
  104. minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
  105. )
  106. func mustBeInteger(what interface{}) *int {
  107. if isJSONNumber(what) {
  108. number := what.(json.Number)
  109. isInt := checkJSONInteger(number)
  110. if isInt {
  111. int64Value, err := number.Int64()
  112. if err != nil {
  113. return nil
  114. }
  115. int32Value := int(int64Value)
  116. return &int32Value
  117. }
  118. }
  119. return nil
  120. }
  121. func mustBeNumber(what interface{}) *big.Rat {
  122. if isJSONNumber(what) {
  123. number := what.(json.Number)
  124. float64Value, success := new(big.Rat).SetString(string(number))
  125. if success {
  126. return float64Value
  127. }
  128. }
  129. return nil
  130. }
  131. func convertDocumentNode(val interface{}) interface{} {
  132. if lval, ok := val.([]interface{}); ok {
  133. res := []interface{}{}
  134. for _, v := range lval {
  135. res = append(res, convertDocumentNode(v))
  136. }
  137. return res
  138. }
  139. if mval, ok := val.(map[interface{}]interface{}); ok {
  140. res := map[string]interface{}{}
  141. for k, v := range mval {
  142. res[k.(string)] = convertDocumentNode(v)
  143. }
  144. return res
  145. }
  146. return val
  147. }