// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // author xeipuuv // author-github https://github.com/xeipuuv // author-mail xeipuuv@gmail.com // // repository-name gojsonschema // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. // // description Various utility functions. // // created 26-02-2013 // nolint: deadcode,unused,varcheck // Package in development (2021). package gojsonschema import ( "encoding/json" "math/big" ) func isStringInSlice(s []string, what string) bool { for i := range s { if s[i] == what { return true } } return false } func marshalToJSONString(value interface{}) (*string, error) { mBytes, err := json.Marshal(value) if err != nil { return nil, err } sBytes := string(mBytes) return &sBytes, nil } func marshalWithoutNumber(value interface{}) (*string, error) { // The JSON is decoded using https://golang.org/pkg/encoding/json/#Decoder.UseNumber // This means the numbers are internally still represented as strings and therefore 1.00 is unequal to 1 // One way to eliminate these differences is to decode and encode the JSON one more time without Decoder.UseNumber // so that these differences in representation are removed jsonString, err := marshalToJSONString(value) if err != nil { return nil, err } var document interface{} err = json.Unmarshal([]byte(*jsonString), &document) if err != nil { return nil, err } return marshalToJSONString(document) } func isJSONNumber(what interface{}) bool { switch what.(type) { case json.Number: return true } return false } func checkJSONInteger(what interface{}) (isInt bool) { jsonNumber := what.(json.Number) bigFloat, isValidNumber := new(big.Rat).SetString(string(jsonNumber)) return isValidNumber && bigFloat.IsInt() } // same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER const ( maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1 minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1 ) func mustBeInteger(what interface{}) *int { number, ok := what.(json.Number) if !ok { return nil } isInt := checkJSONInteger(number) if !isInt { return nil } int64Value, err := number.Int64() if err != nil { return nil } // This doesn't actually convert to an int32 value; it converts to the // system-specific default integer. Assuming this is a valid int32 could cause // bugs. int32Value := int(int64Value) return &int32Value } func mustBeNumber(what interface{}) *big.Rat { number, ok := what.(json.Number) if !ok { return nil } float64Value, success := new(big.Rat).SetString(string(number)) if success { return float64Value } return nil } func convertDocumentNode(val interface{}) interface{} { if lval, ok := val.([]interface{}); ok { res := []interface{}{} for _, v := range lval { res = append(res, convertDocumentNode(v)) } return res } if mval, ok := val.(map[interface{}]interface{}); ok { res := map[string]interface{}{} for k, v := range mval { res[k.(string)] = convertDocumentNode(v) } return res } return val }