dry-types-json-schema 0.0.1 → 0.0.3
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 +4 -4
- data/.github/workflows/test.yml +12 -0
- data/.gitignore +1 -0
- data/Gemfile.lock +11 -1
- data/dry-types-json-schema.gemspec +2 -1
- data/lib/dry/types/extensions/json_schema.rb +62 -20
- data/spec/extensions/json_schema_spec.rb +38 -0
- data/spec/spec_helper.rb +11 -1
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3c596c245aad8cb72bc10fbe904078ac01c7522d14c135b4a6645a7b7f5c769
|
4
|
+
data.tar.gz: 5fc2b32368fdcb1135b32fdb7d3db27c2104966ff371f020eea750df08588b4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50ed4c3ca20040b4d88ae5ecf107c6ccfad7ae7242a724f1c3afd9f015f63a7b203966571af8699614881f7848a657d322554bbb541ff48244194662a73c40e1
|
7
|
+
data.tar.gz: 4810a8578cfecb91df93f66b4a9ad6748db42ef0ebd219c1dfce4eeb52c9fd6992027925579dea2f545b57b38f851eca600ef1eb898ba0a5f114e8d42c14537f
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dry-types-json-schema (0.0.
|
4
|
+
dry-types-json-schema (0.0.3)
|
5
5
|
dry-types (~> 1.7.2)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
ast (2.4.2)
|
11
|
+
attr_extras (7.1.0)
|
11
12
|
base64 (0.2.0)
|
12
13
|
bigdecimal (3.1.7)
|
13
14
|
coderay (1.1.3)
|
14
15
|
concurrent-ruby (1.2.3)
|
16
|
+
diff-lcs (1.5.1)
|
15
17
|
docile (1.4.0)
|
16
18
|
dry-core (1.0.1)
|
17
19
|
concurrent-ruby (~> 1.0)
|
@@ -45,10 +47,13 @@ GEM
|
|
45
47
|
language_server-protocol (3.17.0.3)
|
46
48
|
method_source (1.0.0)
|
47
49
|
minitest (5.22.3)
|
50
|
+
optimist (3.1.0)
|
48
51
|
parallel (1.24.0)
|
49
52
|
parser (3.3.0.5)
|
50
53
|
ast (~> 2.4.1)
|
51
54
|
racc
|
55
|
+
patience_diff (1.2.0)
|
56
|
+
optimist (~> 3.0)
|
52
57
|
pry (0.14.2)
|
53
58
|
coderay (~> 1.1)
|
54
59
|
method_source (~> 1.0)
|
@@ -81,6 +86,10 @@ GEM
|
|
81
86
|
simplecov_json_formatter (0.1.4)
|
82
87
|
simpleidn (0.2.1)
|
83
88
|
unf (~> 0.1.4)
|
89
|
+
super_diff (0.11.0)
|
90
|
+
attr_extras (>= 6.2.4)
|
91
|
+
diff-lcs
|
92
|
+
patience_diff
|
84
93
|
unf (0.1.4)
|
85
94
|
unf_ext
|
86
95
|
unf_ext (0.0.9.1)
|
@@ -100,6 +109,7 @@ DEPENDENCIES
|
|
100
109
|
rubocop (~> 1.62.1)
|
101
110
|
rubocop-minitest (~> 0.35.0)
|
102
111
|
simplecov (~> 0.22.0)
|
112
|
+
super_diff (~> 0.11.0)
|
103
113
|
|
104
114
|
BUNDLED WITH
|
105
115
|
2.5.3
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "dry-types-json-schema"
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.3"
|
6
6
|
s.summary = "Generate JSON Schema from dry-types"
|
7
7
|
s.authors = ["elcuervo"]
|
8
8
|
s.licenses = %w[MIT]
|
@@ -20,4 +20,5 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.add_development_dependency("simplecov", "~> 0.22.0")
|
21
21
|
s.add_development_dependency("rubocop", "~> 1.62.1")
|
22
22
|
s.add_development_dependency("rubocop-minitest", "~> 0.35.0")
|
23
|
+
s.add_development_dependency("super_diff", "~> 0.11.0")
|
23
24
|
end
|
@@ -71,14 +71,13 @@ module Dry
|
|
71
71
|
lt?: { exclusiveMaximum: IDENTITY },
|
72
72
|
lteq?: { maximum: IDENTITY },
|
73
73
|
format?: { format: INSPECT },
|
74
|
-
included_in?: { enum: TO_ARRAY }
|
74
|
+
included_in?: { enum: TO_ARRAY }
|
75
75
|
}.freeze
|
76
76
|
|
77
77
|
# @return [Set] the set of required keys for the JSON Schema.
|
78
78
|
#
|
79
79
|
attr_reader :required
|
80
80
|
|
81
|
-
|
82
81
|
# Initializes a new instance of the JSONSchema class.
|
83
82
|
# @param root [Boolean] whether this schema is the root schema.
|
84
83
|
# @param loose [Boolean] whether to ignore unknown predicates.
|
@@ -141,10 +140,7 @@ module Dry
|
|
141
140
|
type, meta = node
|
142
141
|
|
143
142
|
if opts.fetch(:key, false)
|
144
|
-
|
145
|
-
@keys[opts[:key]] ||= {}
|
146
|
-
@keys[opts[:key]].merge!(meta.slice(*ALLOWED_TYPES_META_OVERRIDES))
|
147
|
-
end
|
143
|
+
visit_nominal_with_key(node, opts)
|
148
144
|
else
|
149
145
|
@keys.merge!(type: CLASS_TO_TYPE[type.to_s.to_sym])
|
150
146
|
@keys.merge!(meta.slice(*ALLOWED_TYPES_META_OVERRIDES)) if meta.any?
|
@@ -175,20 +171,20 @@ module Dry
|
|
175
171
|
@keys[ctx].merge!(definition)
|
176
172
|
end
|
177
173
|
|
178
|
-
def
|
174
|
+
def visit_intersection(node, opts = EMPTY_HASH)
|
179
175
|
*types, _ = node
|
180
176
|
|
181
|
-
|
182
|
-
#
|
183
|
-
process = -> (type) do
|
184
|
-
self.class.new
|
185
|
-
.tap { |target| target.visit(type, opts) }
|
186
|
-
.to_hash
|
187
|
-
.values
|
188
|
-
.first
|
189
|
-
end
|
177
|
+
result = types.map { |type| compile_type(type) }
|
190
178
|
|
191
|
-
|
179
|
+
@keys[opts[:key]] = deep_merge_items(result)
|
180
|
+
end
|
181
|
+
|
182
|
+
def visit_sum(node, opts = EMPTY_HASH)
|
183
|
+
*types, _ = node
|
184
|
+
|
185
|
+
result = types
|
186
|
+
.map { |type| compile_value(type, opts.merge(sum: true)) }
|
187
|
+
.uniq
|
192
188
|
|
193
189
|
return @keys[opts[:key]] = result.first if result.count == 1
|
194
190
|
|
@@ -216,7 +212,10 @@ module Dry
|
|
216
212
|
|
217
213
|
def visit_struct(node, opts = EMPTY_HASH)
|
218
214
|
_, schema = node
|
219
|
-
|
215
|
+
|
216
|
+
return visit(schema, opts) unless opts[:key]
|
217
|
+
|
218
|
+
@keys[opts[:key]] = compile_type(schema)
|
220
219
|
end
|
221
220
|
|
222
221
|
def visit_array(node, opts = EMPTY_HASH)
|
@@ -254,6 +253,49 @@ module Dry
|
|
254
253
|
|
255
254
|
visit(rest, opts.merge(key: name))
|
256
255
|
end
|
256
|
+
|
257
|
+
private
|
258
|
+
|
259
|
+
def deep_merge_items(items)
|
260
|
+
items.reduce({}) do |current, target|
|
261
|
+
current.merge(target) do |_, from, to|
|
262
|
+
case [from.class, to.class]
|
263
|
+
when [::Hash, ::Hash]
|
264
|
+
deep_merge_items([from, to])
|
265
|
+
when [::Array, ::Array]
|
266
|
+
from | to
|
267
|
+
else
|
268
|
+
to
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def compile_type(type, opts = EMPTY_HASH)
|
275
|
+
self.class.new
|
276
|
+
.tap { |target| target.visit(type, opts) }
|
277
|
+
.to_hash
|
278
|
+
end
|
279
|
+
|
280
|
+
def compile_value(type, opts = EMPTY_HASH)
|
281
|
+
compile_type(type, opts)
|
282
|
+
.values
|
283
|
+
.first
|
284
|
+
end
|
285
|
+
|
286
|
+
def visit_nominal_with_key(node, opts = EMPTY_HASH)
|
287
|
+
type, meta = node
|
288
|
+
|
289
|
+
if opts[:array] && !opts[:sum]
|
290
|
+
@keys[opts[:key]] ||= {}
|
291
|
+
@keys[opts[:key]].merge!(items: { type: CLASS_TO_TYPE[type.to_s.to_sym] })
|
292
|
+
end
|
293
|
+
|
294
|
+
if meta.any?
|
295
|
+
@keys[opts[:key]] ||= {}
|
296
|
+
@keys[opts[:key]].merge!(meta.slice(*ALLOWED_TYPES_META_OVERRIDES))
|
297
|
+
end
|
298
|
+
end
|
257
299
|
end
|
258
300
|
|
259
301
|
# The `Builder` module provides a method to generate a JSON Schema hash from dry-types definitions.
|
@@ -263,8 +305,8 @@ module Dry
|
|
263
305
|
# @param options [Hash] Initialization options passed to `JSONSchema.new`
|
264
306
|
# @return [Hash] The generated JSON Schema as a hash.
|
265
307
|
#
|
266
|
-
def json_schema(
|
267
|
-
compiler = JSONSchema.new(
|
308
|
+
def json_schema(root: false, loose: false)
|
309
|
+
compiler = JSONSchema.new(root: root, loose: loose)
|
268
310
|
compiler.call(to_ast)
|
269
311
|
compiler.to_hash
|
270
312
|
end
|
@@ -66,6 +66,13 @@ describe Dry::Types::JSONSchema do
|
|
66
66
|
.constrained(format: /\A[\w+\-.]+@[a-z\d-]+(\.[a-z]+)*\.[a-z]+\z/i)
|
67
67
|
.meta(description: "The internally used pattern")
|
68
68
|
|
69
|
+
ArrayOfStrings = Types::Array
|
70
|
+
.of(Types::String)
|
71
|
+
.constrained(min_size: 1)
|
72
|
+
|
73
|
+
BasicHash = Types::Hash.schema(name: Types::String)
|
74
|
+
ExtendedHash = Types::Hash.schema(age: Types::Integer) & BasicHash
|
75
|
+
|
69
76
|
attribute :data, Types::String | Types::Hash
|
70
77
|
attribute :string, Types::String.constrained(min_size: 1, max_size: 255)
|
71
78
|
attribute :list, VariableList
|
@@ -76,6 +83,12 @@ describe Dry::Types::JSONSchema do
|
|
76
83
|
attribute? :epoch, Types::Time
|
77
84
|
attribute? :meta, Types::String.meta(format: :email)
|
78
85
|
attribute? :enum, Types::String.enum(*%w[draft published archived])
|
86
|
+
attribute? :array, ArrayOfStrings
|
87
|
+
attribute? :inter, ExtendedHash
|
88
|
+
|
89
|
+
attribute? :nested do
|
90
|
+
attribute :deep, Types::Integer
|
91
|
+
end
|
79
92
|
end
|
80
93
|
|
81
94
|
let(:type) { StructTest }
|
@@ -146,6 +159,31 @@ describe Dry::Types::JSONSchema do
|
|
146
159
|
enum: {
|
147
160
|
type: :string,
|
148
161
|
enum: %w[draft published archived]
|
162
|
+
},
|
163
|
+
|
164
|
+
array: {
|
165
|
+
type: :array,
|
166
|
+
minItems: 1,
|
167
|
+
items: { type: :string }
|
168
|
+
},
|
169
|
+
|
170
|
+
inter: {
|
171
|
+
type: :object,
|
172
|
+
properties: {
|
173
|
+
age: { type: :integer },
|
174
|
+
name: { type: :string }
|
175
|
+
},
|
176
|
+
required: %i[age name]
|
177
|
+
},
|
178
|
+
|
179
|
+
nested: {
|
180
|
+
type: :object,
|
181
|
+
properties: {
|
182
|
+
deep: { type: :integer }
|
183
|
+
},
|
184
|
+
required: [:deep],
|
185
|
+
title: "Title",
|
186
|
+
description: "description"
|
149
187
|
}
|
150
188
|
},
|
151
189
|
|
data/spec/spec_helper.rb
CHANGED
@@ -6,6 +6,7 @@ SimpleCov.start
|
|
6
6
|
|
7
7
|
require "minitest/autorun"
|
8
8
|
require "json_schemer"
|
9
|
+
require "super_diff"
|
9
10
|
|
10
11
|
require "dry/struct"
|
11
12
|
require "dry/types"
|
@@ -13,13 +14,22 @@ require "dry/types/extensions"
|
|
13
14
|
|
14
15
|
Dry::Types.load_extensions(:json_schema)
|
15
16
|
|
17
|
+
module Minitest::Assertions
|
18
|
+
def assert_equal_diff(expected, actual, msg = nil)
|
19
|
+
assert_equal(expected, actual, msg)
|
20
|
+
rescue Minitest::Assertion => e
|
21
|
+
puts SuperDiff::Differs::Main.call(expected, actual)
|
22
|
+
raise e
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
16
26
|
class Minitest::Spec
|
17
27
|
class << self
|
18
28
|
def it_conforms_definition(&block)
|
19
29
|
instance_exec(&block) if block
|
20
30
|
|
21
31
|
describe "conforms the schema definition" do
|
22
|
-
it {
|
32
|
+
it { assert_equal_diff type.json_schema, definition }
|
23
33
|
it { assert JSONSchemer.schema(type.json_schema.to_json).valid_schema? }
|
24
34
|
end
|
25
35
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-types-json-schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- elcuervo
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: 0.35.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: super_diff
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.11.0
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.11.0
|
125
139
|
description:
|
126
140
|
email:
|
127
141
|
- elcuervo@elcuervo.net
|
@@ -129,6 +143,7 @@ executables: []
|
|
129
143
|
extensions: []
|
130
144
|
extra_rdoc_files: []
|
131
145
|
files:
|
146
|
+
- ".github/workflows/test.yml"
|
132
147
|
- ".gitignore"
|
133
148
|
- ".rubocop.yml"
|
134
149
|
- Gemfile
|