From 1d2df475117a1ff478f5e36ddeb8c35bce7b3305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Skrzypi=C5=84ski?= Date: Wed, 23 Oct 2024 18:59:25 +0200 Subject: [PATCH] Add "description" and "additionalProperties" to Schema JSONGenerator (#46) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add "description" and "additionalProperties" to Schema JSONGenerator * Update README in section Generating JSON Schema --------- Co-authored-by: Kamil SkrzypiƄski --- README.md | 32 +++++++++++-------- lib/shale/mapping/dict_base.rb | 4 ++- lib/shale/schema/json_generator/boolean.rb | 3 +- lib/shale/schema/json_generator/collection.rb | 3 +- lib/shale/schema/json_generator/date.rb | 4 ++- lib/shale/schema/json_generator/float.rb | 3 +- lib/shale/schema/json_generator/integer.rb | 3 +- lib/shale/schema/json_generator/object.rb | 2 ++ lib/shale/schema/json_generator/string.rb | 3 +- lib/shale/schema/json_generator/time.rb | 4 ++- lib/shale/schema/json_generator/value.rb | 3 +- .../schema/json_generator/boolean_spec.rb | 28 ++++++++++++++-- .../schema/json_generator/collection_spec.rb | 3 +- .../shale/schema/json_generator/float_spec.rb | 2 ++ .../schema/json_generator/object_spec.rb | 4 +++ .../schema/json_generator/string_spec.rb | 2 ++ 16 files changed, 78 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index cb1dc55..89ff01e 100644 --- a/README.md +++ b/README.md @@ -1421,12 +1421,12 @@ class PersonMapper < Shale::Mapper attribute :age, :integer json do - properties max_properties: 5 + properties max_properties: 5, additional_properties: false map "first_name", to: :first_name, schema: { required: true } map "last_name", to: :last_name, schema: { required: true } - map "address", to: :age, schema: { max_length: 128 } - map "age", to: :age, schema: { minimum: 1, maximum: 150 } + map "address", to: :address, schema: { max_length: 128, description: "Street, home number, city and country" } + map "age", to: :age, schema: { minimum: 1, maximum: 150, description: "Person age" } end end @@ -1444,7 +1444,6 @@ Shale::Schema.to_json( # "$defs": { # "Person": { # "type": "object", -# "maxProperties": 5, # "properties": { # "first_name": { # "type": "string" @@ -1452,23 +1451,30 @@ Shale::Schema.to_json( # "last_name": { # "type": "string" # }, -# "age": { +# "address": { # "type": [ -# "integer", +# "string", # "null" # ], -# "minimum": 1, -# "maximum": 150 -# }, -# "address": { +# "maxLength": 128, +# "description": "Street, home number, city and country" +# }, +# "age": { # "type": [ -# "string", +# "integer", # "null" # ], -# "maxLength": 128 +# "minimum": 1, +# "maximum": 150, +# "description": "Person age" # } # }, -# "required": ["first_name", "last_name"] +# "required": [ +# "first_name", +# "last_name" +# ], +# "maxProperties": 5, +# "additionalProperties": false # } # } # } diff --git a/lib/shale/mapping/dict_base.rb b/lib/shale/mapping/dict_base.rb index 72ea800..1512cef 100644 --- a/lib/shale/mapping/dict_base.rb +++ b/lib/shale/mapping/dict_base.rb @@ -67,13 +67,15 @@ def map(key, to: nil, receiver: nil, using: nil, group: nil, render_nil: nil, sc # @param [Integer] min_properties # @param [Integer] max_properties # @param [Hash] dependent_required + # @param [Boolean] additional_properties # # @api public - def properties(min_properties: nil, max_properties: nil, dependent_required: nil) + def properties(min_properties: nil, max_properties: nil, dependent_required: nil, additional_properties: nil) @root = { min_properties: min_properties, max_properties: max_properties, dependent_required: dependent_required, + additional_properties: additional_properties, } end diff --git a/lib/shale/schema/json_generator/boolean.rb b/lib/shale/schema/json_generator/boolean.rb index 196aebe..07831f1 100644 --- a/lib/shale/schema/json_generator/boolean.rb +++ b/lib/shale/schema/json_generator/boolean.rb @@ -15,7 +15,8 @@ class Boolean < Base # # @api private def as_type - { 'type' => 'boolean' } + { 'type' => 'boolean', + 'description' => schema[:description] }.compact end end end diff --git a/lib/shale/schema/json_generator/collection.rb b/lib/shale/schema/json_generator/collection.rb index 6fb0891..2058fc3 100644 --- a/lib/shale/schema/json_generator/collection.rb +++ b/lib/shale/schema/json_generator/collection.rb @@ -46,7 +46,8 @@ def as_json 'maxItems' => schema[:max_items], 'uniqueItems' => schema[:unique], 'minContains' => schema[:min_contains], - 'maxContains' => schema[:max_contains] }.compact + 'maxContains' => schema[:max_contains], + 'description' => schema[:description] }.compact end end end diff --git a/lib/shale/schema/json_generator/date.rb b/lib/shale/schema/json_generator/date.rb index 188544b..7b3f0b3 100644 --- a/lib/shale/schema/json_generator/date.rb +++ b/lib/shale/schema/json_generator/date.rb @@ -15,7 +15,9 @@ class Date < Base # # @api private def as_type - { 'type' => 'string', 'format' => 'date' } + { 'type' => 'string', + 'format' => 'date', + 'description' => schema[:description] }.compact end end end diff --git a/lib/shale/schema/json_generator/float.rb b/lib/shale/schema/json_generator/float.rb index a258a38..301a166 100644 --- a/lib/shale/schema/json_generator/float.rb +++ b/lib/shale/schema/json_generator/float.rb @@ -20,7 +20,8 @@ def as_type 'exclusiveMaximum' => schema[:exclusive_maximum], 'minimum' => schema[:minimum], 'maximum' => schema[:maximum], - 'multipleOf' => schema[:multiple_of] }.compact + 'multipleOf' => schema[:multiple_of], + 'description' => schema[:description] }.compact end end end diff --git a/lib/shale/schema/json_generator/integer.rb b/lib/shale/schema/json_generator/integer.rb index 41cff17..ddd647c 100644 --- a/lib/shale/schema/json_generator/integer.rb +++ b/lib/shale/schema/json_generator/integer.rb @@ -20,7 +20,8 @@ def as_type 'exclusiveMaximum' => schema[:exclusive_maximum], 'minimum' => schema[:minimum], 'maximum' => schema[:maximum], - 'multipleOf' => schema[:multiple_of] }.compact + 'multipleOf' => schema[:multiple_of], + 'description' => schema[:description] }.compact end end end diff --git a/lib/shale/schema/json_generator/object.rb b/lib/shale/schema/json_generator/object.rb index 6ac320a..66d9ac0 100644 --- a/lib/shale/schema/json_generator/object.rb +++ b/lib/shale/schema/json_generator/object.rb @@ -40,6 +40,8 @@ def as_type 'minProperties' => @root[:min_properties], 'maxProperties' => @root[:max_properties], 'dependentRequired' => @root[:dependent_required], + 'description' => @root[:description], + 'additionalProperties' => @root[:additional_properties], }.compact end end diff --git a/lib/shale/schema/json_generator/string.rb b/lib/shale/schema/json_generator/string.rb index 1b30203..555e849 100644 --- a/lib/shale/schema/json_generator/string.rb +++ b/lib/shale/schema/json_generator/string.rb @@ -19,7 +19,8 @@ def as_type 'format' => schema[:format], 'minLength' => schema[:min_length], 'maxLength' => schema[:max_length], - 'pattern' => schema[:pattern] }.compact + 'pattern' => schema[:pattern], + 'description' => schema[:description] }.compact end end end diff --git a/lib/shale/schema/json_generator/time.rb b/lib/shale/schema/json_generator/time.rb index f1e4757..eaf6773 100644 --- a/lib/shale/schema/json_generator/time.rb +++ b/lib/shale/schema/json_generator/time.rb @@ -15,7 +15,9 @@ class Time < Base # # @api private def as_type - { 'type' => 'string', 'format' => 'date-time' } + { 'type' => 'string', + 'format' => 'date-time', + 'description' => schema[:description] }.compact end end end diff --git a/lib/shale/schema/json_generator/value.rb b/lib/shale/schema/json_generator/value.rb index a05b337..acb771a 100644 --- a/lib/shale/schema/json_generator/value.rb +++ b/lib/shale/schema/json_generator/value.rb @@ -15,7 +15,8 @@ class Value < Base # # @api private def as_type - { 'type' => %w[boolean integer number object string] } + { 'type' => %w[boolean integer number object string], + 'description' => schema[:description] }.compact end end end diff --git a/spec/shale/schema/json_generator/boolean_spec.rb b/spec/shale/schema/json_generator/boolean_spec.rb index d83917d..ecdd7af 100644 --- a/spec/shale/schema/json_generator/boolean_spec.rb +++ b/spec/shale/schema/json_generator/boolean_spec.rb @@ -5,8 +5,32 @@ RSpec.describe Shale::Schema::JSONGenerator::Boolean do describe '#as_type' do it 'returns JSON Schema fragment as Hash' do - expected = { 'type' => 'boolean' } - expect(described_class.new('foo').as_type).to eq(expected) + expect(described_class.new('foo').as_type).to eq({ 'type' => 'boolean' }) + end + + context 'when schema is passed' do + it 'can include string keywords from JSON schema' do + schema = { + description: 'Attribute description', + } + expected = { + 'type' => 'boolean', + 'description' => 'Attribute description', + } + expect(described_class.new('foo', schema: schema).as_type).to eq(expected) + end + + it 'can use a subset of schema keywords' do + schema = {} + expected = { 'type' => 'boolean' } + expect(described_class.new('foo', schema: schema).as_type).to eq(expected) + end + + it 'will not use keywords for other types' do + schema = { unique_items: true } + expected = { 'type' => 'boolean' } + expect(described_class.new('foo', schema: schema).as_type).to eq(expected) + end end end end diff --git a/spec/shale/schema/json_generator/collection_spec.rb b/spec/shale/schema/json_generator/collection_spec.rb index edfc68b..7585cc8 100644 --- a/spec/shale/schema/json_generator/collection_spec.rb +++ b/spec/shale/schema/json_generator/collection_spec.rb @@ -26,6 +26,7 @@ unique: true, min_contains: 5, max_contains: 10, + description: 'Attribute description', } expected = { 'type' => 'array', @@ -35,7 +36,7 @@ 'uniqueItems' => true, 'minContains' => 5, 'maxContains' => 10, - + 'description' => 'Attribute description', } expect(described_class.new(type, schema: schema).as_json).to eq(expected) end diff --git a/spec/shale/schema/json_generator/float_spec.rb b/spec/shale/schema/json_generator/float_spec.rb index 1b5e542..6da74fc 100644 --- a/spec/shale/schema/json_generator/float_spec.rb +++ b/spec/shale/schema/json_generator/float_spec.rb @@ -17,6 +17,7 @@ minimum: 0, maximum: 100, multiple_of: 4, + description: 'Attribute description', } expected = { 'type' => 'number', @@ -25,6 +26,7 @@ 'minimum' => 0, 'maximum' => 100, 'multipleOf' => 4, + 'description' => 'Attribute description', } expect(described_class.new('foo', schema: schema).as_type).to eq(expected) end diff --git a/spec/shale/schema/json_generator/object_spec.rb b/spec/shale/schema/json_generator/object_spec.rb index cc8249b..9acdf3c 100644 --- a/spec/shale/schema/json_generator/object_spec.rb +++ b/spec/shale/schema/json_generator/object_spec.rb @@ -53,12 +53,16 @@ 'properties' => { 'bar' => { 'type' => %w[boolean null] }, }, + 'description' => 'Attribute description', + 'additionalProperties' => false, } root = { min_properties: 1, max_properties: 5, dependent_required: { 'foo' => ['bar'] }, + description: 'Attribute description', + additional_properties: false, } expect(described_class.new('foo', types, root).as_type).to eq(expected) diff --git a/spec/shale/schema/json_generator/string_spec.rb b/spec/shale/schema/json_generator/string_spec.rb index 1378f72..b723830 100644 --- a/spec/shale/schema/json_generator/string_spec.rb +++ b/spec/shale/schema/json_generator/string_spec.rb @@ -15,6 +15,7 @@ min_length: 5, max_length: 10, pattern: 'foo-bar', + description: 'Attribute description', } expected = { 'type' => 'string', @@ -22,6 +23,7 @@ 'minLength' => 5, 'maxLength' => 10, 'pattern' => 'foo-bar', + 'description' => 'Attribute description', } expect(described_class.new('foo', schema: schema).as_type).to eq(expected) end