json_schema_view 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +58 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +18 -0
- data/LICENSE.md +202 -0
- data/README.md +117 -0
- data/Rakefile +12 -0
- data/json_schema_view.gemspec +42 -0
- data/lib/json_schema_view/base_component.rb +82 -0
- data/lib/json_schema_view/base_props.rb +32 -0
- data/lib/json_schema_view/configuration/schema_set_dictionary.rb +51 -0
- data/lib/json_schema_view/configuration.rb +44 -0
- data/lib/json_schema_view/json_schema_definable.rb +22 -0
- data/lib/json_schema_view/json_world_extensions/additional_properties.rb +58 -0
- data/lib/json_schema_view/json_world_extensions/any_of.rb +41 -0
- data/lib/json_schema_view/json_world_extensions/camelizable.rb +36 -0
- data/lib/json_schema_view/json_world_extensions/compact_optional_properties.rb +20 -0
- data/lib/json_schema_view/json_world_extensions/constant_property.rb +39 -0
- data/lib/json_schema_view/json_world_extensions/declarable.rb +55 -0
- data/lib/json_schema_view/json_world_extensions/enum_type.rb +45 -0
- data/lib/json_schema_view/json_world_extensions/map_type.rb +47 -0
- data/lib/json_schema_view/json_world_extensions/validatable.rb +17 -0
- data/lib/json_schema_view/json_world_extensions.rb +31 -0
- data/lib/json_schema_view/rails/generators/install/USAGE +5 -0
- data/lib/json_schema_view/rails/generators/install/install_generator.rb +50 -0
- data/lib/json_schema_view/rails/generators/install/templates/base_component.rb.tt +17 -0
- data/lib/json_schema_view/rails/generators/install/templates/base_props.rb.tt +7 -0
- data/lib/json_schema_view/rails/generators/install/templates/component_schema_set.rb.tt +25 -0
- data/lib/json_schema_view/rails/generators/install/templates/example/todo_item_resource.rb +52 -0
- data/lib/json_schema_view/rails/generators/install/templates/example/todo_list_component.rb +67 -0
- data/lib/json_schema_view/rails/generators/install/templates/initializer.rb.tt +15 -0
- data/lib/json_schema_view/rails/generators.rb +8 -0
- data/lib/json_schema_view/rails/rails_engine.rb +20 -0
- data/lib/json_schema_view/rails/tasks/json_schema_component.rake +9 -0
- data/lib/json_schema_view/rails.rb +8 -0
- data/lib/json_schema_view/renderers/base.rb +27 -0
- data/lib/json_schema_view/renderers/json.rb +28 -0
- data/lib/json_schema_view/renderers/react_on_rails.rb +17 -0
- data/lib/json_schema_view/renderers.rb +22 -0
- data/lib/json_schema_view/schema_set/constant_search_helper.rb +114 -0
- data/lib/json_schema_view/schema_set.rb +58 -0
- data/lib/json_schema_view/version.rb +5 -0
- data/lib/json_schema_view.rb +29 -0
- data/sig/json_schema_view.rbs +4 -0
- metadata +134 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
module JsonSchemaView
|
6
|
+
class Configuration
|
7
|
+
# :nodoc:
|
8
|
+
class SchemaSetDictionary < Delegator
|
9
|
+
attr_reader :hash
|
10
|
+
|
11
|
+
# @param contents [Hash, nil]
|
12
|
+
def initialize(contents = nil)
|
13
|
+
@hash = ActiveSupport::HashWithIndifferentAccess.new(contents)
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
# @overload {Delegator#__getobj__}
|
18
|
+
# @return [HashWithIndifferentAccess{Symbol => Symbol}]
|
19
|
+
def __getobj__
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
|
23
|
+
# @overload {Delegator#__setobj__}
|
24
|
+
def __setobj__(_)
|
25
|
+
# noop
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param key [#to_sym] The alias name of SchemaSet
|
29
|
+
# @param value [String, Symbol] The name of SchemaSet class
|
30
|
+
def []=(key, value)
|
31
|
+
raise TypeError, "key (#{key}) cannot be converted to a symbol" unless key.respond_to?(:to_sym)
|
32
|
+
|
33
|
+
if !value.is_a?(String) && !value.is_a?(Symbol)
|
34
|
+
raise TypeError,
|
35
|
+
"value (#{value}) must be the name of SchemaSet class"
|
36
|
+
end
|
37
|
+
|
38
|
+
hash[key.to_sym] = value.to_sym
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [SchemaSet]
|
42
|
+
def fetch_instance(key)
|
43
|
+
klass = fetch(key).constantize
|
44
|
+
|
45
|
+
raise TypeError, "#{klass} is not the name of SchemaSet class" unless klass < JsonSchemaView::SchemaSet
|
46
|
+
|
47
|
+
klass.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonSchemaView
|
4
|
+
# The singleton holds the configuration for the gem.
|
5
|
+
# it can be accessed by both its class methods and Rails's configuration.
|
6
|
+
class Configuration
|
7
|
+
require_relative "configuration/schema_set_dictionary"
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# @return [JsonSchemaView::Configuration]
|
11
|
+
def instance
|
12
|
+
@instance ||= new
|
13
|
+
end
|
14
|
+
|
15
|
+
# @yield [configuration]
|
16
|
+
# @yieldparam configuration [JsonSchemaView::Configuration]
|
17
|
+
def configure(&block)
|
18
|
+
instance.configure(&block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@schema_sets = SchemaSetDictionary.new
|
24
|
+
@validate_by_default = false
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [SchemaSetDictionary{Symbol => Symbol}] The renderers.
|
28
|
+
attr_reader :schema_sets
|
29
|
+
|
30
|
+
# @return [Boolean] Whether if validate components with its schema on render by default.
|
31
|
+
attr_accessor :validate_by_default
|
32
|
+
|
33
|
+
# @param new_sets [Hash{String, Symbol => String, Symbol}]
|
34
|
+
def schema_sets=(new_sets)
|
35
|
+
@schema_sets = SchemaSetDictionary.new(new_sets)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @yield [configuration]
|
39
|
+
# @yieldparam configuration [JsonSchemaView::Configuration]
|
40
|
+
def configure
|
41
|
+
yield self
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json_world"
|
4
|
+
|
5
|
+
require_relative "json_world_extensions"
|
6
|
+
|
7
|
+
module JsonSchemaView
|
8
|
+
# @abstract
|
9
|
+
module JsonSchemaDefinable
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
include ::JsonWorld::DSL
|
13
|
+
include JsonWorldExtensions::Schema202012
|
14
|
+
include JsonWorldExtensions::CompactOptionalProperties
|
15
|
+
include JsonWorldExtensions::Camelizable
|
16
|
+
include JsonWorldExtensions::Validatable
|
17
|
+
|
18
|
+
included do
|
19
|
+
additional_properties(false)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support"
|
4
|
+
|
5
|
+
module JsonSchemaView
|
6
|
+
module JsonWorldExtensions
|
7
|
+
# Define JSON Schema's additionalProperties property.
|
8
|
+
# @see https://json-schema.org/understanding-json-schema/reference/object.html#additional-properties
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# class Zoo
|
12
|
+
# include JsonWorld::DSL
|
13
|
+
# include JsonSchemaView::JsonWorldExtensions::MapType::DSL
|
14
|
+
#
|
15
|
+
# additional_properties(false)
|
16
|
+
# property(
|
17
|
+
# :dogMap,
|
18
|
+
# type: map_type(Dog),
|
19
|
+
# )
|
20
|
+
# end
|
21
|
+
module AdditionalProperties
|
22
|
+
extend ActiveSupport::Concern
|
23
|
+
|
24
|
+
class_methods do
|
25
|
+
# @override {Class.override}
|
26
|
+
def inherited(child)
|
27
|
+
super
|
28
|
+
child.additional_properties(additional_properties)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return the additionalProperties property.
|
32
|
+
# Set the additionalProperties property if arguments are given.
|
33
|
+
# @see https://json-schema.org/draft/2020-12/json-schema-core.html#additionalProperties
|
34
|
+
# @see https://json-schema.org/understanding-json-schema/reference/object.html#id5
|
35
|
+
#
|
36
|
+
# @param value [false, Hash]
|
37
|
+
# @param value_keywords [Hash]
|
38
|
+
def additional_properties(value = nil, **value_keywords)
|
39
|
+
return @additional_properties = value unless value.nil?
|
40
|
+
return @additional_properties = value_keywords unless value_keywords.empty?
|
41
|
+
|
42
|
+
@additional_properties
|
43
|
+
end
|
44
|
+
|
45
|
+
# @override {JsonWorld::DSL::ClassMethods#as_json_schema}
|
46
|
+
def as_json_schema
|
47
|
+
# Do not allow undefined properities.
|
48
|
+
# @see https://json-schema.org/understanding-json-schema/reference/object.html#additionalproperties
|
49
|
+
if @additional_properties.nil?
|
50
|
+
super
|
51
|
+
else
|
52
|
+
super.merge("additionalProperties": @additional_properties)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonSchemaView
|
4
|
+
module JsonWorldExtensions
|
5
|
+
# This class implements `anyOf` schema composition.
|
6
|
+
# Instances of this class acts as an json world compatible object and prints the schema for anyOf combination.
|
7
|
+
# @see https://json-schema.org/understanding-json-schema/reference/combining.html#id6
|
8
|
+
# @example
|
9
|
+
# class Zoo
|
10
|
+
# include JsonWorld::DSL
|
11
|
+
# include JsonSchemaView::JsonWorldExtensions::MapType::DSL
|
12
|
+
# property(
|
13
|
+
# :animal,
|
14
|
+
# type: any_of.new(Dog, Cat),
|
15
|
+
# )
|
16
|
+
# end
|
17
|
+
class AnyOf
|
18
|
+
module DSL
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
class_methods do
|
22
|
+
def any_of(*types)
|
23
|
+
JsonWorldExtensions::AnyOf.new(*types)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :types
|
29
|
+
|
30
|
+
def initialize(*types)
|
31
|
+
@types = types
|
32
|
+
end
|
33
|
+
|
34
|
+
def as_json_schema
|
35
|
+
{ "anyOf" => types.map(&:as_json_schema) }
|
36
|
+
end
|
37
|
+
|
38
|
+
alias as_json_schema_without_links as_json_schema
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support"
|
4
|
+
|
5
|
+
module JsonSchemaView
|
6
|
+
module JsonWorldExtensions
|
7
|
+
# Make the object to be serialized with camelized properties.
|
8
|
+
module Camelizable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
# @param (see JsonWorld::DSL::ClassMethods#property)
|
13
|
+
# @param camelize [Boolean] if true, camelize the property name on json format.
|
14
|
+
def property(raw_property_name, camelize: true, **options)
|
15
|
+
raw_property_name = raw_property_name.to_sym
|
16
|
+
property_name = camelize ? camelize_name(raw_property_name) : raw_property_name
|
17
|
+
|
18
|
+
super(property_name, **options)
|
19
|
+
|
20
|
+
# Define a method with camelized name as an alias of the method with raw name.
|
21
|
+
if camelize && property_name != raw_property_name
|
22
|
+
define_method(property_name) do
|
23
|
+
public_send(raw_property_name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param name [String, Symbol]
|
29
|
+
# @return [Symbol]
|
30
|
+
def camelize_name(name)
|
31
|
+
ActiveSupport::Inflector.camelize(name.to_s, false).to_sym
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonSchemaView
|
4
|
+
module JsonWorldExtensions
|
5
|
+
# This module automatically removes properties with null value from encoded json if the property is optional.
|
6
|
+
#
|
7
|
+
# JSON Schema distinguishs a optional property and a nullable property.
|
8
|
+
# If the value of a optional property is empty, you should remove the property from the encoded json.
|
9
|
+
# This module make safe such the optional properties.
|
10
|
+
# @see https://json-schema.org/understanding-json-schema/reference/object.html#required-properties
|
11
|
+
module CompactOptionalProperties
|
12
|
+
# @note Overrides {JsonWorld::JsonEncodable#properties}
|
13
|
+
def properties(options)
|
14
|
+
optional_property_names = self.class.property_definitions.select(&:optional?).map(&:property_name)
|
15
|
+
|
16
|
+
super(options).reject { |key, value| value.nil? && optional_property_names.include?(key) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonSchemaView
|
4
|
+
module JsonWorldExtensions
|
5
|
+
# This module allows {JsonWorld::DSL::ClassMethods#property} to define constant values.
|
6
|
+
# Defined constant values are reflect to JSON Schema.
|
7
|
+
# @see https://json-schema.org/understanding-json-schema/reference/generic.html#constant-values
|
8
|
+
module ConstantProperty
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
# If property is defined with `const` parameter, define an instance method to return the value.
|
13
|
+
# @note Overrides {JsonWorld::DSL::ClassMethods#property}
|
14
|
+
def property(name, **options)
|
15
|
+
if options[:const]
|
16
|
+
const = options[:const].freeze
|
17
|
+
define_method(name) { const }
|
18
|
+
end
|
19
|
+
|
20
|
+
super(name, **options)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Add constant values informations JSON Schema
|
24
|
+
# @note Overrides {JsonWorld::DSL::ClassMethods#as_json_schema}
|
25
|
+
def as_json_schema
|
26
|
+
property_hash = property_definitions.map do |property|
|
27
|
+
if (const = property.raw_options[:const])
|
28
|
+
# For now, use enumerated values instead of constant values.
|
29
|
+
[property.property_name, { const: const }]
|
30
|
+
else
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end.compact.to_h
|
34
|
+
super.deep_merge(properties: property_hash)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonSchemaView
|
4
|
+
module JsonWorldExtensions
|
5
|
+
# Add methods to declare a common schema. Declared schema are exported as `$defs` property.
|
6
|
+
#
|
7
|
+
# @see: https://json-schema.org/understanding-json-schema/structuring.html#defs
|
8
|
+
module Declarable
|
9
|
+
extend ::ActiveSupport::Concern
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
attr_writer :declarations
|
13
|
+
|
14
|
+
# @override {Class.inherited}
|
15
|
+
def inherited(child)
|
16
|
+
super
|
17
|
+
child.declarations = declarations.clone
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param type_or_name [Class<JsonWorld::DSL>, Symbol]
|
21
|
+
# @param (see JsonWorld::DSL::ClassMethods#property)
|
22
|
+
def declare(type_or_name, **options)
|
23
|
+
property_type = options[:type] || type_or_name
|
24
|
+
property_name = type_or_name.is_a?(Module) ? type_or_name.name.demodulize.to_sym : type_or_name.to_sym
|
25
|
+
|
26
|
+
declaration = JsonWorld::PropertyDefinition.new(property_name: property_name, type: property_type, **options)
|
27
|
+
declarations << declaration
|
28
|
+
end
|
29
|
+
|
30
|
+
# @override {JsonWorld::DSL::ClassMethods#as_json_schema}
|
31
|
+
def as_json_schema
|
32
|
+
decls = declarations_as_json_schema
|
33
|
+
if decls.present?
|
34
|
+
super.merge("$defs": decls)
|
35
|
+
else
|
36
|
+
super
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def declarations_as_json_schema
|
41
|
+
declarations.inject({}) do |result, declaration|
|
42
|
+
result.merge(
|
43
|
+
declaration.property_name => declaration.as_json_schema,
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [Array<PropertyDefinition>]
|
49
|
+
def declarations
|
50
|
+
@declarations ||= []
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonSchemaView
|
4
|
+
module JsonWorldExtensions
|
5
|
+
# This module allows {JsonWorld::DSL::ClassMethods#property} to define enum values.
|
6
|
+
# Defined constant values are reflect to JSON Schema.
|
7
|
+
# @see https://json-schema.org/understanding-json-schema/reference/generic.html#enumerated-values
|
8
|
+
# @example
|
9
|
+
# class Zoo
|
10
|
+
# include JsonWorld::DSL
|
11
|
+
# include JsonSchemaView::JsonWorldExtensions::EnumType::DSL
|
12
|
+
# property(
|
13
|
+
# :animal,
|
14
|
+
# type: enum_type("Dog", "Cat"),
|
15
|
+
# )
|
16
|
+
# end
|
17
|
+
class EnumType
|
18
|
+
module DSL
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
class_methods do
|
22
|
+
def enum_type(*args)
|
23
|
+
JsonWorldExtensions::EnumType.new(*args)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :candidates
|
29
|
+
|
30
|
+
# @param type [String, Symbol, #as_json_schema]
|
31
|
+
# @param candidates [Array<Object>]
|
32
|
+
def initialize(*candidates)
|
33
|
+
@candidates = candidates
|
34
|
+
end
|
35
|
+
|
36
|
+
def as_json_schema
|
37
|
+
{
|
38
|
+
enum: candidates
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
alias as_json_schema_without_links as_json_schema
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonSchemaView
|
4
|
+
module JsonWorldExtensions
|
5
|
+
# This class implements map type (string keys to values with the given type) in JSON Schema.
|
6
|
+
# You can specify the type of values but you cannot specify the type of keys,
|
7
|
+
# because JSON and JSON Schema only support String keys in objects.
|
8
|
+
#
|
9
|
+
# @see https://json-schema.org/understanding-json-schema/reference/object.html#additional-properties
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# class Zoo
|
13
|
+
# include JsonWorld::DSL
|
14
|
+
# include JsonSchemaView::JsonWorldExtensions::MapType::DSL
|
15
|
+
# property(
|
16
|
+
# :dogMap,
|
17
|
+
# type: map_type(Dog),
|
18
|
+
# )
|
19
|
+
# end
|
20
|
+
class MapType
|
21
|
+
module DSL
|
22
|
+
extend ActiveSupport::Concern
|
23
|
+
|
24
|
+
class_methods do
|
25
|
+
def map_type(type)
|
26
|
+
JsonWorldExtensions::MapType.new(type)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :type
|
32
|
+
|
33
|
+
def initialize(type)
|
34
|
+
@type = type
|
35
|
+
end
|
36
|
+
|
37
|
+
def as_json_schema
|
38
|
+
{
|
39
|
+
type: "object",
|
40
|
+
additionalProperties: JsonWorld::PropertyDefinition.new(type: type).as_json_schema
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
alias as_json_schema_without_links as_json_schema
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "json-schema"
|
5
|
+
|
6
|
+
module JsonSchemaView
|
7
|
+
module JsonWorldExtensions
|
8
|
+
# Add method to validate self properties with {JSON::Validator}.
|
9
|
+
module Validatable
|
10
|
+
# @raise [JSON::Schema::ValidationError] if self is not valid.
|
11
|
+
# @return [void]
|
12
|
+
def validate_json!
|
13
|
+
JSON::Validator.validate!(self.class.as_json_schema, as_json)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support"
|
4
|
+
|
5
|
+
module JsonSchemaView
|
6
|
+
# A collection of extensions for {JsonWorld::DSL} to support recent JSON Schema.
|
7
|
+
# @private
|
8
|
+
module JsonWorldExtensions
|
9
|
+
require_relative "json_world_extensions/additional_properties"
|
10
|
+
require_relative "json_world_extensions/any_of"
|
11
|
+
require_relative "json_world_extensions/camelizable"
|
12
|
+
require_relative "json_world_extensions/compact_optional_properties"
|
13
|
+
require_relative "json_world_extensions/constant_property"
|
14
|
+
require_relative "json_world_extensions/declarable"
|
15
|
+
require_relative "json_world_extensions/enum_type"
|
16
|
+
require_relative "json_world_extensions/map_type"
|
17
|
+
require_relative "json_world_extensions/validatable"
|
18
|
+
|
19
|
+
# @see https://json-schema.org/specification.html
|
20
|
+
module Schema202012
|
21
|
+
extend ActiveSupport::Concern
|
22
|
+
|
23
|
+
include AdditionalProperties
|
24
|
+
include AnyOf::DSL
|
25
|
+
include ConstantProperty
|
26
|
+
include Declarable
|
27
|
+
include EnumType::DSL
|
28
|
+
include MapType::DSL
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
|
5
|
+
module JsonSchemaView
|
6
|
+
module Generators
|
7
|
+
# Install files to setup json_schema_view gem.
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
9
|
+
source_root File.expand_path("templates", __dir__)
|
10
|
+
|
11
|
+
class_option :components_path, type: :string, default: "app/components"
|
12
|
+
class_option :export_path, type: :string, default: "json_schema"
|
13
|
+
class_option :renderer_type, type: :string, default: "react_on_rails"
|
14
|
+
|
15
|
+
def create_initializer
|
16
|
+
template "initializer.rb", "config/initializers/json_schema_view.rb"
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_base_classes
|
20
|
+
template "base_component.rb", File.join(components_path, "base_component.rb")
|
21
|
+
template "base_props.rb", File.join(components_path, "base_props.rb")
|
22
|
+
template "component_schema_set.rb", File.join(components_path, "component_schema_set.rb")
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_exmaples
|
26
|
+
template "example/todo_list_component.rb", File.join(components_path, "example_todo_list_component.rb")
|
27
|
+
template "example/todo_item_resource.rb",
|
28
|
+
File.join(components_path, "example_todo_list_component", "todo_item_resource.rb")
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def components_path
|
34
|
+
options[:components_path]
|
35
|
+
end
|
36
|
+
|
37
|
+
def export_path
|
38
|
+
options[:export_path]
|
39
|
+
end
|
40
|
+
|
41
|
+
def renderer_type
|
42
|
+
options[:renderer_type]
|
43
|
+
end
|
44
|
+
|
45
|
+
def schema_set_class_name
|
46
|
+
"ComponentSchemaSet"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json_schema_view"
|
4
|
+
|
5
|
+
# @abstract
|
6
|
+
class BaseComponent < ::JsonSchemaView::BaseComponent
|
7
|
+
# You can configure how this components is rendered.
|
8
|
+
#
|
9
|
+
# There are some preset renderers:
|
10
|
+
# * `:json` - serialize the component as json text.
|
11
|
+
# * `:react_on_rails` - render the component by using react_on_rails gem.
|
12
|
+
renderer_class(:<%= renderer_type %>)
|
13
|
+
|
14
|
+
def base_props_class
|
15
|
+
BaseProps
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json_schema_view"
|
4
|
+
|
5
|
+
# Configure what resource to export its JSON Schema and where directory to export.
|
6
|
+
class <%= schema_set_class_name %> < ::JsonSchemaView::SchemaSet
|
7
|
+
# <%= schema_set_class_name %> looks up component classses in this directory.
|
8
|
+
def root_path
|
9
|
+
__dir__
|
10
|
+
end
|
11
|
+
|
12
|
+
# <%= schema_set_class_name %> exports JSON Schema of these component classes.
|
13
|
+
def resource_classes_to_export
|
14
|
+
[
|
15
|
+
# Export all component classes (except for BaseComopnent) in `root_path`.
|
16
|
+
*search_component_classes.excluding(BaseComponent),
|
17
|
+
# You can add extra classes including {JsonSchemaDefinable} here to export their JSON Schemas.
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
# <%= schema_set_class_name %> exports JSON Schema to this directory.
|
22
|
+
def export_path
|
23
|
+
Rails.root.join("<%= export_path %>")
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json_schema_view"
|
4
|
+
|
5
|
+
class ExampleTodoListComponent
|
6
|
+
# This is an example definition of a resource.
|
7
|
+
#
|
8
|
+
# A class that includes {JsonSchemaView::JsonSchemaDefinable} can generate its JSON Schema
|
9
|
+
# and it can be used as a type in another resource's property.
|
10
|
+
class TodoItemResource
|
11
|
+
include JsonSchemaView::JsonSchemaDefinable
|
12
|
+
|
13
|
+
property(
|
14
|
+
:name,
|
15
|
+
description: "The title of TODO item.",
|
16
|
+
type: String,
|
17
|
+
)
|
18
|
+
|
19
|
+
property(
|
20
|
+
:done,
|
21
|
+
description: "Whether the TODO item is done or not.",
|
22
|
+
type: [TrueClass, FalseClass],
|
23
|
+
)
|
24
|
+
|
25
|
+
property(
|
26
|
+
:note,
|
27
|
+
description: "The additional description of TODO item.",
|
28
|
+
type: String,
|
29
|
+
optional: true,
|
30
|
+
)
|
31
|
+
|
32
|
+
# @param todo_item [Hash] A todo item ({ name: String, done: Boolean, note: String or nil }).
|
33
|
+
def initialize(todo_item)
|
34
|
+
@todo_item = todo_item
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [String] The title of TODO item.
|
38
|
+
def title
|
39
|
+
@todo_item[:title]
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Boolean] Whether the TODO item is done or not.
|
43
|
+
def done
|
44
|
+
@todo_item[:done]
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param note [String, nil] The additional description of TODO item.
|
48
|
+
def note
|
49
|
+
@todo_item[:note]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|