Files
apinto/utils/json.go

348 lines
8.4 KiB
Go

package utils
import (
"encoding/json"
"errors"
"fmt"
"github.com/brianvoe/gofakeit/v6"
"math/rand"
"strconv"
"strings"
"time"
"github.com/robertkrimen/otto"
)
// JSObjectToJSON 将js对象转为json
func JSObjectToJSON(s string) ([]byte, error) {
vm := otto.New()
v, err := vm.Run(fmt.Sprintf(`
cs = %s
JSON.stringify(cs)
`, s))
if err != nil {
return nil, err
}
return []byte(v.String()), nil
}
// JSONUnmarshal 将json格式的s解码成v所需的json格式
func JSONUnmarshal(s, v interface{}) error {
data, err := json.Marshal(s)
if err != nil {
return err
}
return json.Unmarshal(data, v)
}
// JsonSchemaMockJsUnmarshal
// 解析mockJs生成的json schema 并根据规则生成随机值
// 不是mockJs生成的json 走默认规则解析
func JsonSchemaMockJsUnmarshal(valueMap interface{}) interface{} {
rand.Seed(time.Now().UnixMicro())
gofakeit.Seed(time.Now().UnixMicro())
value, vOk := valueMap.(map[string]interface{})
if vOk {
switch valType := value["properties"].(type) {
case []interface{}:
resultMap := make(map[string]interface{})
for _, v := range valType {
if m, ok := v.(map[string]interface{}); ok {
name, nameOk := m["name"].(string)
if !nameOk {
return jsonSchemaFormat
}
template := m["template"]
if t, tOk := m["type"].(string); tOk {
rule, ruleOk := m["rule"].(map[string]interface{})
if !ruleOk || len(rule) == 0 {
if template != nil {
resultMap[name] = mockConstant(template)
continue
}
}
switch t {
case "string":
minVal, maxVal, _, _, err := getMinMaxDminDmax(rule)
if err != nil {
return err
}
randomNum := 0
if minVal > 0 && maxVal == 0 {
randomNum = int(minVal)
}
if minVal > 0 && maxVal > 0 {
randomNum = int(RandInt64(int64(minVal), int64(maxVal)))
}
if template != nil {
templateStr, sOk := template.(string)
if !sOk {
return jsonSchemaFormat
}
temp := ""
for i := 0; i < randomNum; i++ {
temp = temp + templateStr
}
resultMap[name] = temp
continue
}
case "number":
minVal, maxVal, dminVal, dmaxVal, err := getMinMaxDminDmax(rule)
if err != nil {
return err
}
randomValue := 0.0
if minVal > 0.0 && maxVal == 0.0 {
randomValue = minVal
randomValue += RandFloats(0, 1)
} else if minVal > 0.0 && maxVal > 0.0 {
randomValue = RandFloats(minVal, maxVal)
}
if randomValue == 0.0 {
resultMap[name] = template
continue
}
if dminVal > 0.0 && dmaxVal == 0.0 {
randomValue, _ = strconv.ParseFloat(strconv.FormatFloat(randomValue, 'f', int(dminVal), 64), 64)
} else if dminVal > 0.0 && dmaxVal > 0.0 {
floats := RandFloats(dminVal, dmaxVal)
randomValue, _ = strconv.ParseFloat(strconv.FormatFloat(randomValue, 'f', int(floats), 64), 64)
} else {
randomValue, _ = strconv.ParseFloat(strconv.FormatFloat(randomValue, 'f', 0, 64), 64)
}
resultMap[name] = randomValue
case "boolean":
resultMap[name] = gofakeit.Bool()
case "object":
templateMap, templateOk := template.(map[string]interface{})
if templateOk {
minVal, maxVal, _, _, err := getMinMaxDminDmax(rule)
if err != nil {
return err
}
randomNum := 0
if minVal > 0 && maxVal == 0 {
randomNum = int(minVal)
}
if minVal > 0 && maxVal > 0 {
randomNum = int(RandInt64(int64(minVal), int64(maxVal)))
}
tempMap := make(map[string]interface{})
i := 1
for key, val := range templateMap {
split := strings.Split(key, "|")
tempMap[split[0]] = mockConstant(val)
if i == randomNum {
break
}
i++
}
resultMap[name] = tempMap
}
case "array":
templateList, templateOk := template.([]interface{})
if templateOk {
minVal, maxVal, _, _, err := getMinMaxDminDmax(rule)
if err != nil {
return err
}
randomNum := 0
if minVal > 0.0 && maxVal == 0.0 {
randomNum = int(minVal)
}
if minVal > 0.0 && maxVal > 0.0 {
randomNum = int(RandInt64(int64(minVal), int64(maxVal)))
}
if randomNum == 1 {
if len(templateList) > 1 {
resultMap[name] = templateList[rand.Intn(len(templateList))]
continue
}
switch templateVal := templateList[0].(type) {
case map[string]interface{}:
tempMap := make(map[string]interface{})
for key, val := range templateVal {
split := strings.Split(key, "|")
tempMap[split[0]] = mockConstant(val)
}
resultMap[name] = tempMap
default:
resultMap[name] = templateVal
}
continue
}
tempList := make([]interface{}, 0)
for i := 0; i < randomNum; i++ {
for _, templateType := range templateList {
switch templateVal := templateType.(type) {
case map[string]interface{}:
tempMap := make(map[string]interface{})
for key, val := range templateVal {
split := strings.Split(key, "|")
tempMap[split[0]] = mockConstant(val)
}
tempList = append(tempList, tempMap)
default:
tempList = append(tempList, templateType)
}
}
}
resultMap[name] = tempList
}
}
}
}
}
return resultMap
}
}
return jsonSchemaUnmarshal(value)
}
func mockConstant(v interface{}) interface{} {
if templateStr, ok := v.(string); ok {
templateStr = strings.ToLower(templateStr)
switch templateStr {
case "@cname":
return gofakeit.Username()
case "@cfirst":
return gofakeit.FirstName()
case "@clast":
return gofakeit.LastName()
case "@name", "@name(true)":
return gofakeit.Name()
case "@first":
return gofakeit.FirstName()
case "@last":
return gofakeit.LastName()
case "@email":
return gofakeit.Email()
case "@ip":
return gofakeit.IPv4Address()
case "@zip":
return gofakeit.Address().Zip
case "@city", "@city(true)":
return gofakeit.Address().Address
case "@url":
return gofakeit.URL()
default:
return v
}
}
return v
}
var jsonSchemaFormat = errors.New("json schema format err")
func getMinMaxDminDmax(rule map[string]interface{}) (float64, float64, float64, float64, error) {
minVal := 0.0
min, minOk := rule["min"]
if minOk && min != nil {
mOk := false
minVal, mOk = min.(float64)
if !mOk {
return 0, 0, 0, 0, jsonSchemaFormat
}
}
maxVal := 0.0
max, maxOk := rule["max"]
if maxOk && max != nil {
mOk := false
maxVal, mOk = max.(float64)
if !mOk {
return 0, 0, 0, 0, jsonSchemaFormat
}
}
dminVal := 0.0
dmin, dminOk := rule["dmin"]
if dminOk && dmin != nil {
mOk := false
dminVal, mOk = dmin.(float64)
if !mOk {
return 0, 0, 0, 0, jsonSchemaFormat
}
}
dmaxVal := 0.0
dmax, dmaxOk := rule["dmax"]
if dmaxOk && dmax != nil {
mOk := false
dmaxVal, mOk = dmax.(float64)
if !mOk {
return 0, 0, 0, 0, jsonSchemaFormat
}
}
return minVal, maxVal, dminVal, dmaxVal, nil
}
func jsonSchemaUnmarshal(properties interface{}) interface{} {
propertiesMap, ok := properties.(map[string]interface{})
if !ok {
return jsonSchemaFormat
}
if val, ok := propertiesMap["example"]; ok {
return val
} else {
if t, tOk := propertiesMap["type"].(string); tOk {
switch t {
case "string":
return gofakeit.LetterN(10)
case "number":
return gofakeit.Float64()
case "integer":
return gofakeit.Int64()
case "boolean":
return gofakeit.Bool()
case "object":
propertiesMaps, pOk := propertiesMap["properties"].(map[string]interface{})
if !pOk {
return jsonSchemaFormat
}
resultMap := make(map[string]interface{})
for key, vProperties := range propertiesMaps {
resultMap[key] = jsonSchemaUnmarshal(vProperties)
}
return resultMap
case "array":
items, iOk := propertiesMap["items"].(map[string]interface{})
if !iOk {
return jsonSchemaFormat
}
resultList := make([]interface{}, 0)
resultList = append(resultList, jsonSchemaUnmarshal(items))
return resultList
}
}
return jsonSchemaFormat
}
}