From 99c235d68439c40bf18552795b6ab28f18c0f547 Mon Sep 17 00:00:00 2001 From: dingwenjiang Date: Sun, 28 Mar 2021 15:35:36 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0.gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + schema.go | 4 ++++ subSchema.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/.gitignore b/.gitignore index 68e993ce..fab45f35 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.sw[nop] *.iml .vscode/ +.idea diff --git a/schema.go b/schema.go index 9e93cd79..27ce30fd 100644 --- a/schema.go +++ b/schema.go @@ -1085,3 +1085,7 @@ func (d *Schema) parseDependencies(documentNode interface{}, currentSchema *subS return nil } + +func (d *Schema) GetSchema() *subSchema { + return d.rootSchema +} \ No newline at end of file diff --git a/subSchema.go b/subSchema.go index ec779812..53a6f125 100644 --- a/subSchema.go +++ b/subSchema.go @@ -27,6 +27,7 @@ package gojsonschema import ( + "encoding/json" "github.com/xeipuuv/gojsonreference" "math/big" "regexp" @@ -147,3 +148,45 @@ type subSchema struct { _then *subSchema _else *subSchema } + +func (v *subSchema) MarshalJSON() ([]byte, error) { + ret := make(map[string]interface{}) + if len(v.property) != 0{ + ret["title"] = v.property + } + if len(v.types.types) > 0 { + ret["type"] = v.types.types[0] + switch ret["type"] { + case "number": + if v.multipleOf != nil{ + ret["multipleOf"] = v.multipleOf + } + if v.maximum != nil { + ret["maximum"] = v.maximum.Num() + } + if v.minimum != nil { + ret["minimum"] = v.minimum.Num() + } + case "string": + if len(v.format) != 0 { + ret["format"] = v.format + } + if v.minLength != nil { + ret["minLength"] = v.minLength + } + if v.maxLength != nil { + ret["maxLength"] = v.maxLength + } + if v.pattern != nil { + ret["pattern"] = v.maxLength + } + case "boolean": + case "object": + } + + + } + return json.Marshal(ret) +} + + From aa9f9a8cfec7a42a32aa56d87e966ebf1c3a0492 Mon Sep 17 00:00:00 2001 From: dingwenjiang Date: Mon, 29 Mar 2021 18:58:53 +0800 Subject: [PATCH 2/2] feat: implement Marshaler & Unmarshaler for schema --- schema.go | 19 ++++++-- subSchema.go | 123 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 112 insertions(+), 30 deletions(-) diff --git a/schema.go b/schema.go index 27ce30fd..303957a5 100644 --- a/schema.go +++ b/schema.go @@ -27,6 +27,7 @@ package gojsonschema import ( + "encoding/json" "errors" "math/big" "reflect" @@ -1086,6 +1087,18 @@ func (d *Schema) parseDependencies(documentNode interface{}, currentSchema *subS return nil } -func (d *Schema) GetSchema() *subSchema { - return d.rootSchema -} \ No newline at end of file +// MarshalJSON convert schema to json +func (d *Schema) MarshalJSON() ([]byte, error) { + return json.Marshal(d.rootSchema) +} + +// UnmarshalJSON convert json to schema +func (d *Schema) UnmarshalJSON(bytes []byte) error { + loader := NewSchemaLoader() + if schema, err := loader.Compile(NewBytesLoader(bytes)); err != nil { + return err + } else { + *d = *schema + return nil + } +} diff --git a/subSchema.go b/subSchema.go index 53a6f125..9fb93f4a 100644 --- a/subSchema.go +++ b/subSchema.go @@ -30,6 +30,7 @@ import ( "encoding/json" "github.com/xeipuuv/gojsonreference" "math/big" + "reflect" "regexp" ) @@ -150,43 +151,111 @@ type subSchema struct { } func (v *subSchema) MarshalJSON() ([]byte, error) { - ret := make(map[string]interface{}) - if len(v.property) != 0{ - ret["title"] = v.property - } + tmp := make(map[string]interface{}) + result := make(map[string]interface{}) if len(v.types.types) > 0 { - ret["type"] = v.types.types[0] - switch ret["type"] { - case "number": - if v.multipleOf != nil{ - ret["multipleOf"] = v.multipleOf - } - if v.maximum != nil { - ret["maximum"] = v.maximum.Num() - } - if v.minimum != nil { - ret["minimum"] = v.minimum.Num() + switch v.types.types[0] { + //case "boolean", "null": // do nothing + case "number", "integer": + // type、multipleOf、minimum、exclusiveMinimum、maximum、exclusiveMaximum + tmp = map[string]interface{}{ + "multipleOf": ensureField(v.multipleOf), + "minimum": ensureField(v.minimum), + "exclusiveMinimum": ensureField(v.exclusiveMinimum), + "maximum": ensureField(v.maximum), + "exclusiveMaximum": ensureField(v.exclusiveMaximum), } case "string": - if len(v.format) != 0 { - ret["format"] = v.format + // type、minLength、maxLength、pattern、format + tmp = map[string]interface{}{ + "minLength": ensureField(v.minLength), + "maxLength": ensureField(v.maxLength), + "pattern": ensureField(v.pattern), + "format": ensureField(v.format), } - if v.minLength != nil { - ret["minLength"] = v.minLength + case "object": + // type、properties、additionalProperties、required, propertyNames、minProperties、 + tmp = map[string]interface{}{ + "minProperties": ensureField(v.minProperties), + "maxProperties": ensureField(v.maxProperties), + "required": ensureField(v.required), + "dependencies": ensureField(v.dependencies), + "additionalProperties": ensureField(v.additionalProperties), + "patternProperties": ensureField(v.patternProperties), + "propertyNames": ensureField(v.propertyNames), } - if v.maxLength != nil { - ret["maxLength"] = v.maxLength + if v.propertiesChildren != nil { + properties := make(map[string]interface{}) + for _, propertyChild := range v.propertiesChildren { + properties[propertyChild.property] = propertyChild + } + tmp["properties"] = properties } - if v.pattern != nil { - ret["pattern"] = v.maxLength + case "array": + tmp = map[string]interface{}{ + "minItems": ensureField(v.minItems), + "maxItems": ensureField(v.maxItems), + "uniqueItems": ensureField(v.uniqueItems), + "contains": ensureField(v.contains), + "additionalItems": ensureField(v.additionalItems), } - case "boolean": - case "object": } + tmp["type"] = v.types.types[0] + tmp["const"] = ensureField(v._const) + tmp["enum"] = ensureField(v.enum) + } + for key, value := range tmp { + if value != nil { + result[key] = value + } + } + return json.Marshal(result) +} - +func ensureField(p interface{}) interface{} { + if isNil(p) { + return nil } - return json.Marshal(ret) + var ret interface{} + rv := reflect.ValueOf(p) + if rv.Kind() == reflect.Ptr { + if rv.Type() == reflect.TypeOf(&big.Rat{}) { + ret = (p.(*big.Rat)).Num() + } else if rv.Type() == reflect.TypeOf(®exp.Regexp{}) { + ret = (p.(*regexp.Regexp)).String() + } else { + switch rv.Elem().Kind() { + case reflect.Int: + ret = *(p.(*int)) + case reflect.String: + ret = *(p.(*string)) + case reflect.Slice, reflect.Interface, reflect.Map: + ret = p + } + } + } else { + switch rv.Kind() { + case reflect.String: + tmp := p.(string) + if len(tmp) != 0 { + ret = tmp + } + case reflect.Slice: + ret = p + } + } + return ret } +func isNil(i interface{}) bool { + // https://mangatmodi.medium.com/go-check-nil-interface-the-right-way-d142776edef1 + if i == nil { + return true + } + switch reflect.TypeOf(i).Kind() { + case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice: + return reflect.ValueOf(i).IsNil() + } + return false +}