dry-types-json-schema 0.0.2 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d53a441b9ed9f57e185e971538b1a3b3f81038527e9f071c7af8fbfb8cd10a3c
4
- data.tar.gz: d6693481b3aaa1d6b5b81b34ae91c90eea58758f094681b68ea11f9fca5ea34c
3
+ metadata.gz: 67e63d34a8b81578fef86941bd3f448062ddf6357f5ea66751882f424a52bd28
4
+ data.tar.gz: 732938510bbdfa5490421cebfff6de06b57108819bdc0f7f7806f03ad4c8131b
5
5
  SHA512:
6
- metadata.gz: 939497ac477bdc404b3ab166f3af9d2f42260617f96f145e73921d0dc721a57cea618d48b4738958b322be5c549268829fda68bd7309487db1e1695f47da3b16
7
- data.tar.gz: 4e86da1db6970398e73fb22ee6d7dd3e1505198705bdcc0cddf28d7df849afcd521703043e6a550e42ee75bd526d30ecf5077d81b048498f914251554095ff26
6
+ metadata.gz: a0133a959fe532c4f5c75a5084c674a2e83553af6e6abb6580a1809fba8f5dd15c748640c786f4d22cd04a00303582ddc3ef957b707ec00d17281621bf4e6ad7
7
+ data.tar.gz: 05b90642aa10bce11add57b7591fa466a0102f9c5d62e4fa29b8a2f0a1318908d0a10baf9c36531fadf5584764d740b0beb3a7e21b540be63eb03a4b23f03ba0
@@ -0,0 +1,12 @@
1
+ name: Test
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ runs-on: ubuntu-latest
6
+ steps:
7
+ - uses: actions/checkout@v4
8
+ - uses: ruby/setup-ruby@v1
9
+ with:
10
+ ruby-version: '3.3'
11
+ bundler-cache: true
12
+ - run: bundle exec make test
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dry-types-json-schema (0.0.2)
4
+ dry-types-json-schema (0.0.4)
5
5
  dry-types (~> 1.7.2)
6
6
 
7
7
  GEM
@@ -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.2"
5
+ s.version = "0.0.4"
6
6
  s.summary = "Generate JSON Schema from dry-types"
7
7
  s.authors = ["elcuervo"]
8
8
  s.licenses = %w[MIT]
@@ -17,7 +17,7 @@ module Dry
17
17
  IDENTITY = ->(v, _) { v }.freeze
18
18
  INSPECT = ->(v, _) { v.inspect }.freeze
19
19
  TO_INTEGER = ->(v, _) { v.to_i }.freeze
20
- TO_ARRAY = ->(v, _) { v.to_a }.freeze
20
+ TO_ARRAY = ->(v, _) { Array(v) }.freeze
21
21
  TO_TYPE = ->(v, _) { CLASS_TO_TYPE.fetch(v.to_s.to_sym) }.freeze
22
22
 
23
23
  # Metadata annotations and allowed types overrides for schema generation.
@@ -161,21 +161,33 @@ module Dry
161
161
 
162
162
  definition.transform_values! { |v| v.call(type, ctx) }
163
163
 
164
- return unless definition.any? && ctx
164
+ return unless definition.any?
165
165
 
166
166
  if (extra = EXTRA_PROPS_FOR_TYPE[type.to_s.to_sym])
167
167
  definition = definition.merge(extra)
168
168
  end
169
169
 
170
- @keys[ctx] ||= {}
171
- @keys[ctx].merge!(definition)
170
+ if ctx.nil?
171
+ @keys.merge!(definition)
172
+ else
173
+ @keys[ctx] ||= {}
174
+ @keys[ctx].merge!(definition)
175
+ end
176
+ end
177
+
178
+ def visit_intersection(node, opts = EMPTY_HASH)
179
+ *types, _ = node
180
+
181
+ result = types.map { |type| compile_type(type) }
182
+
183
+ @keys[opts[:key]] = deep_merge_items(result)
172
184
  end
173
185
 
174
186
  def visit_sum(node, opts = EMPTY_HASH)
175
187
  *types, _ = node
176
188
 
177
189
  result = types
178
- .map { |type| single_type(type, opts.merge(sum: true)) }
190
+ .map { |type| compile_value(type, opts.merge(sum: true)) }
179
191
  .uniq
180
192
 
181
193
  return @keys[opts[:key]] = result.first if result.count == 1
@@ -205,14 +217,9 @@ module Dry
205
217
  def visit_struct(node, opts = EMPTY_HASH)
206
218
  _, schema = node
207
219
 
208
- if opts[:key]
209
- target = self.class.new
210
- target.visit(schema)
220
+ return visit(schema, opts) unless opts[:key]
211
221
 
212
- @keys[opts[:key]] = target.to_hash
213
- else
214
- visit(schema, opts)
215
- end
222
+ @keys[opts[:key]] = compile_type(schema)
216
223
  end
217
224
 
218
225
  def visit_array(node, opts = EMPTY_HASH)
@@ -253,12 +260,29 @@ module Dry
253
260
 
254
261
  private
255
262
 
256
- # FIXME: cleaner way to generate individual types
257
- #
258
- def single_type(type, opts)
263
+ def deep_merge_items(items)
264
+ items.reduce({}) do |current, target|
265
+ current.merge(target) do |_, from, to|
266
+ case [from.class, to.class]
267
+ when [::Hash, ::Hash]
268
+ deep_merge_items([from, to])
269
+ when [::Array, ::Array]
270
+ from | to
271
+ else
272
+ to
273
+ end
274
+ end
275
+ end
276
+ end
277
+
278
+ def compile_type(type, opts = EMPTY_HASH)
259
279
  self.class.new
260
280
  .tap { |target| target.visit(type, opts) }
261
281
  .to_hash
282
+ end
283
+
284
+ def compile_value(type, opts = EMPTY_HASH)
285
+ compile_type(type, opts)
262
286
  .values
263
287
  .first
264
288
  end
@@ -16,6 +16,14 @@ describe Dry::Types::JSONSchema do
16
16
  { type: :string, format: :email, title: title }
17
17
  end
18
18
  end
19
+
20
+ it_conforms_definition do
21
+ let(:type) { Dry::Types["string"].enum(*%w[a b]) }
22
+
23
+ let(:definition) do
24
+ { type: :string, enum: %w[a b] }
25
+ end
26
+ end
19
27
  end
20
28
 
21
29
  describe "hash" do
@@ -70,6 +78,9 @@ describe Dry::Types::JSONSchema do
70
78
  .of(Types::String)
71
79
  .constrained(min_size: 1)
72
80
 
81
+ BasicHash = Types::Hash.schema(name: Types::String)
82
+ ExtendedHash = Types::Hash.schema(age: Types::Integer) & BasicHash
83
+
73
84
  attribute :data, Types::String | Types::Hash
74
85
  attribute :string, Types::String.constrained(min_size: 1, max_size: 255)
75
86
  attribute :list, VariableList
@@ -81,6 +92,8 @@ describe Dry::Types::JSONSchema do
81
92
  attribute? :meta, Types::String.meta(format: :email)
82
93
  attribute? :enum, Types::String.enum(*%w[draft published archived])
83
94
  attribute? :array, ArrayOfStrings
95
+ attribute? :inter, ExtendedHash
96
+
84
97
  attribute? :nested do
85
98
  attribute :deep, Types::Integer
86
99
  end
@@ -162,6 +175,15 @@ describe Dry::Types::JSONSchema do
162
175
  items: { type: :string }
163
176
  },
164
177
 
178
+ inter: {
179
+ type: :object,
180
+ properties: {
181
+ age: { type: :integer },
182
+ name: { type: :string }
183
+ },
184
+ required: %i[age name]
185
+ },
186
+
165
187
  nested: {
166
188
  type: :object,
167
189
  properties: {
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.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - elcuervo
@@ -143,6 +143,7 @@ executables: []
143
143
  extensions: []
144
144
  extra_rdoc_files: []
145
145
  files:
146
+ - ".github/workflows/test.yml"
146
147
  - ".gitignore"
147
148
  - ".rubocop.yml"
148
149
  - Gemfile