From bd9a93154641d4ecc7c77f1be828465c2df7e0fa Mon Sep 17 00:00:00 2001 From: webdestroya Date: Sun, 9 Oct 2022 00:15:43 -0700 Subject: [PATCH 1/3] feat(reflect): Add method to modify the schema after processing --- fixtures/custom_type_post.json | 23 +++++++++++++++++++++++ reflect.go | 22 ++++++++++++++++++++++ reflect_test.go | 20 ++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 fixtures/custom_type_post.json diff --git a/fixtures/custom_type_post.json b/fixtures/custom_type_post.json new file mode 100644 index 0000000..de1ce36 --- /dev/null +++ b/fixtures/custom_type_post.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/invopop/jsonschema/schema-post-test", + "$ref": "#/$defs/SchemaPostTest", + "$defs": { + "SchemaPostTest": { + "properties": { + "LastName": { + "type": "string", + "description": "some extra words" + }, + "middle_name": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "LastName" + ] + } + } +} \ No newline at end of file diff --git a/reflect.go b/reflect.go index af36886..a8dc6f6 100644 --- a/reflect.go +++ b/reflect.go @@ -108,7 +108,14 @@ type customSchemaImpl interface { JSONSchema() *Schema } +// Function to be run after the schema has been generated. +// this will let you modify a schema afterwards +type postSchemaImpl interface { + JSONSchemaPost(*Schema) +} + var customType = reflect.TypeOf((*customSchemaImpl)(nil)).Elem() +var postType = reflect.TypeOf((*postSchemaImpl)(nil)).Elem() // customSchemaGetFieldDocString type customSchemaGetFieldDocString interface { @@ -395,6 +402,8 @@ func (r *Reflector) reflectTypeToSchema(definitions Definitions, t reflect.Type) panic("unsupported type " + t.String()) } + r.reflectSchemaPost(definitions, t, st) + // Always try to reference the definition which may have just been created if def := r.refDefinition(definitions, t); def != nil { return def @@ -422,6 +431,19 @@ func (r *Reflector) reflectCustomSchema(definitions Definitions, t reflect.Type) return nil } +func (r *Reflector) reflectSchemaPost(definitions Definitions, t reflect.Type, s *Schema) *Schema { + if t.Implements(postType) { + v := reflect.New(t) + o := v.Interface().(postSchemaImpl) + o.JSONSchemaPost(s) + if ref := r.refDefinition(definitions, t); ref != nil { + return ref + } + } + + return s +} + func (r *Reflector) reflectSliceOrArray(definitions Definitions, t reflect.Type, st *Schema) { if t == rawMessageType { return diff --git a/reflect_test.go b/reflect_test.go index 1442bd3..349b767 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -295,6 +295,25 @@ type KeyNamed struct { RenamedByComputation int `jsonschema_description:"Description was preserved"` } +type SchemaPostTestBase struct { + FirstName string `json:"FirstName"` + LastName string `json:"LastName"` + Age uint `json:"age"` + MiddleName string `json:"middle_name,omitempty"` +} + +type SchemaPostTest struct { + SchemaPostTestBase `json:",inline"` +} + +func (SchemaPostTest) JSONSchemaPost(base *Schema) { + base.Properties.Delete("FirstName") + base.Properties.Delete("age") + val, _ := base.Properties.Get("LastName") + (val).(*Schema).Description = "some extra words" + base.Required = []string{"LastName"} +} + func TestReflector(t *testing.T) { r := new(Reflector) s := "http://example.com/schema" @@ -424,6 +443,7 @@ func TestSchemaGeneration(t *testing.T) { }, "fixtures/keynamed.json"}, {MapType{}, &Reflector{}, "fixtures/map_type.json"}, {ArrayType{}, &Reflector{}, "fixtures/array_type.json"}, + {SchemaPostTest{}, &Reflector{}, "fixtures/custom_type_post.json"}, } for _, tt := range tests { From b32bc839da77c370e4a9153d0e4f4cb755c2839c Mon Sep 17 00:00:00 2001 From: webdestroya Date: Tue, 8 Nov 2022 00:48:28 -0800 Subject: [PATCH 2/3] Renaming JSONSchemaPost to JSONSchemaExtend --- reflect.go | 16 ++++++++-------- reflect_test.go | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/reflect.go b/reflect.go index a8dc6f6..7545697 100644 --- a/reflect.go +++ b/reflect.go @@ -110,12 +110,12 @@ type customSchemaImpl interface { // Function to be run after the schema has been generated. // this will let you modify a schema afterwards -type postSchemaImpl interface { - JSONSchemaPost(*Schema) +type extendSchemaImpl interface { + JSONSchemaExtend(*Schema) } var customType = reflect.TypeOf((*customSchemaImpl)(nil)).Elem() -var postType = reflect.TypeOf((*postSchemaImpl)(nil)).Elem() +var extendType = reflect.TypeOf((*extendSchemaImpl)(nil)).Elem() // customSchemaGetFieldDocString type customSchemaGetFieldDocString interface { @@ -402,7 +402,7 @@ func (r *Reflector) reflectTypeToSchema(definitions Definitions, t reflect.Type) panic("unsupported type " + t.String()) } - r.reflectSchemaPost(definitions, t, st) + r.reflectSchemaExtend(definitions, t, st) // Always try to reference the definition which may have just been created if def := r.refDefinition(definitions, t); def != nil { @@ -431,11 +431,11 @@ func (r *Reflector) reflectCustomSchema(definitions Definitions, t reflect.Type) return nil } -func (r *Reflector) reflectSchemaPost(definitions Definitions, t reflect.Type, s *Schema) *Schema { - if t.Implements(postType) { +func (r *Reflector) reflectSchemaExtend(definitions Definitions, t reflect.Type, s *Schema) *Schema { + if t.Implements(extendType) { v := reflect.New(t) - o := v.Interface().(postSchemaImpl) - o.JSONSchemaPost(s) + o := v.Interface().(extendSchemaImpl) + o.JSONSchemaExtend(s) if ref := r.refDefinition(definitions, t); ref != nil { return ref } diff --git a/reflect_test.go b/reflect_test.go index 349b767..645a78d 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -306,7 +306,7 @@ type SchemaPostTest struct { SchemaPostTestBase `json:",inline"` } -func (SchemaPostTest) JSONSchemaPost(base *Schema) { +func (SchemaPostTest) JSONSchemaExtend(base *Schema) { base.Properties.Delete("FirstName") base.Properties.Delete("age") val, _ := base.Properties.Get("LastName") From ea9462d7d8a12b6c001ebc60356efb128da36050 Mon Sep 17 00:00:00 2001 From: webdestroya Date: Tue, 8 Nov 2022 00:52:54 -0800 Subject: [PATCH 3/3] fixes --- .../{custom_type_post.json => custom_type_extend.json} | 6 +++--- reflect_test.go | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) rename fixtures/{custom_type_post.json => custom_type_extend.json} (74%) diff --git a/fixtures/custom_type_post.json b/fixtures/custom_type_extend.json similarity index 74% rename from fixtures/custom_type_post.json rename to fixtures/custom_type_extend.json index de1ce36..a1dc9d4 100644 --- a/fixtures/custom_type_post.json +++ b/fixtures/custom_type_extend.json @@ -1,9 +1,9 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/invopop/jsonschema/schema-post-test", - "$ref": "#/$defs/SchemaPostTest", + "$id": "https://github.com/invopop/jsonschema/schema-extend-test", + "$ref": "#/$defs/SchemaExtendTest", "$defs": { - "SchemaPostTest": { + "SchemaExtendTest": { "properties": { "LastName": { "type": "string", diff --git a/reflect_test.go b/reflect_test.go index d62ea19..c0d2c9f 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -310,18 +310,18 @@ type KeyNamed struct { RenamedByComputation int `jsonschema_description:"Description was preserved"` } -type SchemaPostTestBase struct { +type SchemaExtendTestBase struct { FirstName string `json:"FirstName"` LastName string `json:"LastName"` Age uint `json:"age"` MiddleName string `json:"middle_name,omitempty"` } -type SchemaPostTest struct { - SchemaPostTestBase `json:",inline"` +type SchemaExtendTest struct { + SchemaExtendTestBase `json:",inline"` } -func (SchemaPostTest) JSONSchemaExtend(base *Schema) { +func (SchemaExtendTest) JSONSchemaExtend(base *Schema) { base.Properties.Delete("FirstName") base.Properties.Delete("age") val, _ := base.Properties.Get("LastName") @@ -463,7 +463,7 @@ func TestSchemaGeneration(t *testing.T) { }, "fixtures/keynamed.json"}, {MapType{}, &Reflector{}, "fixtures/map_type.json"}, {ArrayType{}, &Reflector{}, "fixtures/array_type.json"}, - {SchemaPostTest{}, &Reflector{}, "fixtures/custom_type_post.json"}, + {SchemaExtendTest{}, &Reflector{}, "fixtures/custom_type_extend.json"}, {Expression{}, &Reflector{}, "fixtures/schema_with_expression.json"}, }