apiwork 0.3.1 → 0.5.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/apiwork/adapter/serializer/resource/base.rb +15 -0
  3. data/lib/apiwork/adapter/serializer/resource/default/contract_builder.rb +4 -3
  4. data/lib/apiwork/adapter/standard/capability/writing/contract_builder.rb +13 -9
  5. data/lib/apiwork/api/base.rb +105 -17
  6. data/lib/apiwork/api/element.rb +35 -4
  7. data/lib/apiwork/api/object.rb +72 -7
  8. data/lib/apiwork/api/router.rb +16 -0
  9. data/lib/apiwork/configuration/validatable.rb +1 -0
  10. data/lib/apiwork/configuration.rb +2 -0
  11. data/lib/apiwork/contract/element.rb +19 -4
  12. data/lib/apiwork/contract/object/coercer.rb +31 -2
  13. data/lib/apiwork/contract/object/deserializer.rb +5 -1
  14. data/lib/apiwork/contract/object/transformer.rb +15 -2
  15. data/lib/apiwork/contract/object/validator.rb +49 -11
  16. data/lib/apiwork/contract/object.rb +79 -9
  17. data/lib/apiwork/element.rb +34 -1
  18. data/lib/apiwork/export/base.rb +1 -4
  19. data/lib/apiwork/export/builder_mapper.rb +184 -0
  20. data/lib/apiwork/export/open_api.rb +9 -2
  21. data/lib/apiwork/export/sorbus.rb +5 -1
  22. data/lib/apiwork/export/sorbus_mapper.rb +3 -7
  23. data/lib/apiwork/export/type_analysis.rb +20 -6
  24. data/lib/apiwork/export/type_script.rb +4 -1
  25. data/lib/apiwork/export/type_script_mapper.rb +25 -2
  26. data/lib/apiwork/export/zod.rb +9 -0
  27. data/lib/apiwork/export/zod_mapper.rb +22 -1
  28. data/lib/apiwork/introspection/api.rb +18 -0
  29. data/lib/apiwork/introspection/dump/action.rb +1 -1
  30. data/lib/apiwork/introspection/dump/api.rb +2 -0
  31. data/lib/apiwork/introspection/dump/param.rb +36 -20
  32. data/lib/apiwork/introspection/dump/resource.rb +7 -4
  33. data/lib/apiwork/introspection/dump/type.rb +31 -25
  34. data/lib/apiwork/introspection/param/array.rb +26 -0
  35. data/lib/apiwork/introspection/param/base.rb +15 -25
  36. data/lib/apiwork/introspection/param/binary.rb +36 -0
  37. data/lib/apiwork/introspection/param/boolean.rb +36 -0
  38. data/lib/apiwork/introspection/param/date.rb +36 -0
  39. data/lib/apiwork/introspection/param/date_time.rb +36 -0
  40. data/lib/apiwork/introspection/param/decimal.rb +26 -0
  41. data/lib/apiwork/introspection/param/integer.rb +26 -0
  42. data/lib/apiwork/introspection/param/number.rb +26 -0
  43. data/lib/apiwork/introspection/param/record.rb +71 -0
  44. data/lib/apiwork/introspection/param/string.rb +26 -0
  45. data/lib/apiwork/introspection/param/time.rb +36 -0
  46. data/lib/apiwork/introspection/param/uuid.rb +36 -0
  47. data/lib/apiwork/introspection/param.rb +1 -0
  48. data/lib/apiwork/introspection.rb +17 -4
  49. data/lib/apiwork/object.rb +246 -4
  50. data/lib/apiwork/representation/attribute.rb +2 -2
  51. data/lib/apiwork/representation/base.rb +107 -2
  52. data/lib/apiwork/representation/element.rb +15 -5
  53. data/lib/apiwork/version.rb +1 -1
  54. metadata +6 -4
@@ -7,8 +7,12 @@ module Apiwork
7
7
  output :string
8
8
  file_extension '.ts'
9
9
 
10
+ option :builders, default: false, type: :boolean
11
+
10
12
  def generate
11
- SorbusMapper.map(self, surface)
13
+ output = SorbusMapper.map(self, surface)
14
+ output += "\n\n#{BuilderMapper.map(self, surface)}" if options[:builders]
15
+ output
12
16
  end
13
17
 
14
18
  private
@@ -37,10 +37,8 @@ module Apiwork
37
37
  end
38
38
 
39
39
  def build_contract
40
- contract = {
41
- endpoints: build_endpoint_tree(@export.api.resources),
42
- error: build_error_schema,
43
- }
40
+ contract = { endpoints: build_endpoint_tree(@export.api.resources) }
41
+ contract[:error] = build_error_schema if @surface.types.key?(:error)
44
42
  "export const contract = #{format_object(contract, indent: 0)} as const;"
45
43
  end
46
44
 
@@ -80,9 +78,7 @@ module Apiwork
80
78
  end
81
79
 
82
80
  def transform_path(path)
83
- path.gsub(%r{(/:?)(\w+)}) do
84
- "#{::Regexp.last_match(1)}#{@export.transform_key(::Regexp.last_match(2))}"
85
- end
81
+ path.to_s.gsub(/:(\w+)/) { ":#{@export.transform_key(::Regexp.last_match(1))}" }
86
82
  end
87
83
 
88
84
  def extract_path_params(path)
@@ -4,9 +4,8 @@ module Apiwork
4
4
  module Export
5
5
  class TypeAnalysis
6
6
  PRIMITIVE_TYPES = %i[
7
- string integer boolean datetime date uuid object array
8
- decimal float literal union enum text binary json number time
9
- unknown
7
+ array binary boolean date datetime decimal enum float integer json
8
+ literal number object record string text time union unknown uuid
10
9
  ].to_set.freeze
11
10
 
12
11
  class << self
@@ -39,11 +38,22 @@ module Apiwork
39
38
 
40
39
  def find_cycle_breaking_types(graph)
41
40
  lazy_types = Set.new
41
+ reduced_graph = graph
42
42
 
43
- find_strongly_connected_components(graph).each do |component|
44
- next if component.size == 1 && !graph[component.first].include?(component.first)
43
+ loop do
44
+ previous_size = lazy_types.size
45
+
46
+ find_strongly_connected_components(reduced_graph).each do |component|
47
+ next if component.size == 1 && !reduced_graph[component.first].include?(component.first)
48
+
49
+ lazy_types.add(select_cycle_breaker(component, reduced_graph))
50
+ end
45
51
 
46
- lazy_types.add(component.min_by(&:to_s))
52
+ break if lazy_types.size == previous_size
53
+
54
+ reduced_graph = reduced_graph
55
+ .reject { |node, _| lazy_types.include?(node) }
56
+ .transform_values { |deps| deps - lazy_types.to_a }
47
57
  end
48
58
 
49
59
  lazy_types
@@ -114,6 +124,10 @@ module Apiwork
114
124
  state[:components] << component
115
125
  end
116
126
 
127
+ def select_cycle_breaker(component, graph)
128
+ component.min_by { |node| [-(graph[node] & component).size, node.to_s] }
129
+ end
130
+
117
131
  def collect_references(node, references, filter)
118
132
  return unless node.is_a?(Hash)
119
133
 
@@ -7,10 +7,13 @@ module Apiwork
7
7
  output :string
8
8
  file_extension '.ts'
9
9
 
10
+ option :builders, default: false, type: :boolean
10
11
  option :version, default: '5', enum: %w[4 5], type: :string
11
12
 
12
13
  def generate
13
- TypeScriptMapper.map(self, surface)
14
+ output = TypeScriptMapper.map(self, surface)
15
+ output += "\n\n#{BuilderMapper.map(self, surface)}" if options[:builders]
16
+ output
14
17
  end
15
18
 
16
19
  private
@@ -30,7 +30,7 @@ module Apiwork
30
30
  ts_type = map_field(param)
31
31
  optional_marker = param.optional? ? '?' : ''
32
32
 
33
- prop_jsdoc = jsdoc(description: param.description, example: param.example)
33
+ prop_jsdoc = jsdoc(description: param.description, example: param.concrete? ? param.example : nil)
34
34
  if prop_jsdoc
35
35
  indented_jsdoc = prop_jsdoc.lines.map { |line| " #{line.chomp}" }.join("\n")
36
36
  "#{indented_jsdoc}\n #{key}#{optional_marker}: #{ts_type};"
@@ -165,6 +165,8 @@ module Apiwork
165
165
  map_object_type(param)
166
166
  elsif param.array?
167
167
  map_array_type(param)
168
+ elsif param.record?
169
+ map_record_type(param)
168
170
  elsif param.union?
169
171
  map_union_type(param)
170
172
  elsif param.literal?
@@ -207,8 +209,29 @@ module Apiwork
207
209
  end
208
210
  end
209
211
 
212
+ def map_record_type(param)
213
+ value_type = param.of ? map_param(param.of) : 'unknown'
214
+ "Record<string, #{value_type}>"
215
+ end
216
+
210
217
  def map_union_type(param)
211
- param.variants.map { |variant| map_param(variant) }.sort.join(' | ')
218
+ variant_types = param.variants.map do |variant|
219
+ if param.discriminator && variant.tag && variant.object?
220
+ discriminator_prop = "#{@export.transform_key(param.discriminator)}: '#{variant.tag}'"
221
+ properties = variant.shape.sort_by { |name, _| name.to_s }.map do |name, field|
222
+ "#{@export.transform_key(name)}: #{map_field(field)}"
223
+ end
224
+ all_properties = [discriminator_prop, *properties].join('; ')
225
+ "{ #{all_properties} }"
226
+ elsif param.discriminator && variant.tag
227
+ base_type = map_param(variant)
228
+ "{ #{@export.transform_key(param.discriminator)}: '#{variant.tag}' } & #{base_type}"
229
+ else
230
+ map_param(variant)
231
+ end
232
+ end
233
+
234
+ variant_types.sort.join(' | ')
212
235
  end
213
236
 
214
237
  def map_literal_type(param)
@@ -7,6 +7,7 @@ module Apiwork
7
7
  output :string
8
8
  file_extension '.ts'
9
9
 
10
+ option :builders, default: false, type: :boolean
10
11
  option :version, default: '4', enum: %w[4], type: :string
11
12
 
12
13
  def generate
@@ -26,6 +27,14 @@ module Apiwork
26
27
  parts << ''
27
28
  end
28
29
 
30
+ if options[:builders]
31
+ builder_output = BuilderMapper.map(self, surface)
32
+ if builder_output.present?
33
+ parts << builder_output
34
+ parts << ''
35
+ end
36
+ end
37
+
29
38
  parts.join("\n")
30
39
  end
31
40
 
@@ -200,6 +200,8 @@ module Apiwork
200
200
  map_object_type(param)
201
201
  elsif param.array?
202
202
  map_array_type(param)
203
+ elsif param.record?
204
+ map_record_type(param)
203
205
  elsif param.union?
204
206
  map_union_type(param)
205
207
  elsif param.literal?
@@ -248,6 +250,11 @@ module Apiwork
248
250
  base
249
251
  end
250
252
 
253
+ def map_record_type(param)
254
+ value_schema = param.of ? map_param(param.of) : 'z.unknown()'
255
+ "z.record(z.string(), #{value_schema})"
256
+ end
257
+
251
258
  def map_union_type(param)
252
259
  if param.discriminator
253
260
  map_discriminated_union(param)
@@ -260,7 +267,21 @@ module Apiwork
260
267
  def map_discriminated_union(param)
261
268
  discriminator_field = @export.transform_key(param.discriminator)
262
269
 
263
- variant_schemas = param.variants.map { |variant| map_param(variant) }
270
+ variant_schemas = param.variants.map do |variant|
271
+ if variant.tag && variant.object?
272
+ discriminator_prop = "#{discriminator_field}: z.literal('#{variant.tag}')"
273
+ properties = variant.shape.sort_by { |name, _| name.to_s }.map do |name, field|
274
+ "#{@export.transform_key(name)}: #{map_field(field)}"
275
+ end
276
+ all_properties = [discriminator_prop, *properties].join(', ')
277
+ "z.object({ #{all_properties} })"
278
+ elsif variant.tag
279
+ base_schema = map_param(variant)
280
+ "#{base_schema}.extend({ #{discriminator_field}: z.literal('#{variant.tag}') })"
281
+ else
282
+ map_param(variant)
283
+ end
284
+ end
264
285
 
265
286
  "z.discriminatedUnion('#{discriminator_field}', [#{variant_schemas.join(', ')}])"
266
287
  end
@@ -33,6 +33,14 @@ module Apiwork
33
33
  @dump[:base_path]
34
34
  end
35
35
 
36
+ # @api public
37
+ # The fingerprint for this API.
38
+ #
39
+ # @return [String]
40
+ def fingerprint
41
+ @dump[:fingerprint]
42
+ end
43
+
36
44
  # @api public
37
45
  # The info for this API.
38
46
  #
@@ -65,6 +73,14 @@ module Apiwork
65
73
  @enums ||= @dump[:enums].transform_values { |dump| Enum.new(dump) }
66
74
  end
67
75
 
76
+ # @api public
77
+ # The supported locales for this API.
78
+ #
79
+ # @return [Array<Symbol>]
80
+ def locales
81
+ @dump[:locales]
82
+ end
83
+
68
84
  # @api public
69
85
  # The error codes for this API.
70
86
  #
@@ -80,6 +96,8 @@ module Apiwork
80
96
  def to_h
81
97
  {
82
98
  base_path:,
99
+ fingerprint:,
100
+ locales:,
83
101
  enums: enums.transform_values(&:to_h),
84
102
  error_codes: error_codes.transform_values(&:to_h),
85
103
  info: info&.to_h,
@@ -52,7 +52,7 @@ module Apiwork
52
52
 
53
53
  def build_response(response)
54
54
  return { body: {}, description: i18n_lookup(:response, :description), no_content: false } unless response
55
- return { body: {}, description: response.description || i18n_lookup(:response, :description), no_content: true } if response.no_content?
55
+ return { body: nil, description: response.description || i18n_lookup(:response, :description), no_content: true } if response.no_content?
56
56
 
57
57
  description = response.description || i18n_lookup(:response, :description)
58
58
  body_shape = response.body
@@ -18,7 +18,9 @@ module Apiwork
18
18
  base_path: @api_class.transform_path(@api_class.base_path),
19
19
  enums: type_dump_hash[:enums],
20
20
  error_codes: build_error_codes(collect_all_error_code_keys(resources)),
21
+ fingerprint: @api_class.fingerprint,
21
22
  info: build_info,
23
+ locales: @api_class.locales,
22
24
  types: type_dump_hash[:types],
23
25
  }
24
26
  end
@@ -162,15 +162,28 @@ module Apiwork
162
162
 
163
163
  result = {
164
164
  reference:,
165
+ as: nil,
166
+ default: nil,
167
+ deprecated: false,
168
+ description: nil,
169
+ discriminator: nil,
165
170
  enum: element.enum,
171
+ example: nil,
166
172
  format: element.format,
167
173
  max: element.max,
168
174
  min: element.min,
175
+ nullable: false,
176
+ of: nil,
177
+ optional: false,
178
+ partial: false,
169
179
  shape: resolved_shape,
180
+ tag: nil,
170
181
  type: reference ? :reference : type_value,
182
+ value: nil,
183
+ variants: [],
171
184
  }
172
185
 
173
- result[:of] = build_of_from_element(element.inner) if element.type == :array && element.inner
186
+ result[:of] = build_of_from_element(element.inner) if [:array, :record].include?(element.type) && element.inner
174
187
 
175
188
  result
176
189
  end
@@ -294,19 +307,39 @@ module Apiwork
294
307
  of = options[:of]
295
308
  return nil unless of
296
309
 
310
+ union = of.type == :union
311
+ union_shape = union && of.shape.is_a?(Apiwork::API::Union) ? of.shape : nil
312
+
297
313
  result = {
314
+ as: nil,
315
+ default: nil,
316
+ deprecated: false,
317
+ description: nil,
318
+ discriminator: union ? of.discriminator : nil,
298
319
  enum: of.enum,
320
+ example: nil,
299
321
  format: of.format,
300
322
  max: of.max,
301
323
  min: of.min,
324
+ nullable: false,
325
+ of: nil,
326
+ optional: false,
327
+ partial: false,
302
328
  reference: nil,
303
- shape: of.shape ? build_nested_shape(of.shape) : {},
329
+ shape: union ? {} : build_of_shape(of),
330
+ tag: nil,
304
331
  type: of.type,
332
+ value: nil,
333
+ variants: union_shape ? union_shape.variants.map { |variant| build_api_variant(variant) } : [],
305
334
  }
306
335
  result[:of] = build_api_of({ of: of.inner }) if of.type == :array && of.inner
307
336
  result
308
337
  end
309
338
 
339
+ def build_of_shape(of)
340
+ of.shape ? build_nested_shape(of.shape) : {}
341
+ end
342
+
310
343
  def build_api_variant(variant)
311
344
  {
312
345
  as: nil,
@@ -320,7 +353,7 @@ module Apiwork
320
353
  max: nil,
321
354
  min: nil,
322
355
  nullable: false,
323
- of: build_api_variant_of(variant),
356
+ of: build_api_of(variant),
324
357
  optional: false,
325
358
  partial: variant[:partial] == true,
326
359
  reference: nil,
@@ -332,23 +365,6 @@ module Apiwork
332
365
  }
333
366
  end
334
367
 
335
- def build_api_variant_of(variant)
336
- of = variant[:of]
337
- return nil unless of
338
-
339
- result = {
340
- enum: of.enum,
341
- format: of.format,
342
- max: of.max,
343
- min: of.min,
344
- reference: nil,
345
- shape: of.shape ? build_nested_shape(of.shape) : {},
346
- type: of.type,
347
- }
348
- result[:of] = build_api_variant_of({ of: of.inner }) if of.type == :array && of.inner
349
- result
350
- end
351
-
352
368
  def build_shape(options)
353
369
  dumped = options[:shape] ? build_nested_shape(options[:shape]) : nil
354
370
 
@@ -4,11 +4,12 @@ module Apiwork
4
4
  module Introspection
5
5
  module Dump
6
6
  class Resource
7
- def initialize(resource, api_class, parent_identifiers: [], parent_param: nil, parent_singular: false)
7
+ def initialize(resource, api_class, parent_identifiers: [], parent_param: nil, parent_path: nil, parent_singular: false)
8
8
  @resource = resource
9
9
  @api_class = api_class
10
10
  @parent_identifiers = parent_identifiers
11
11
  @parent_param = parent_param
12
+ @parent_path = parent_path
12
13
  @parent_singular = parent_singular
13
14
  end
14
15
 
@@ -57,10 +58,11 @@ module Apiwork
57
58
  end
58
59
 
59
60
  def build_resource_path(formatted_segment)
60
- return formatted_segment if @parent_identifiers.empty?
61
- return formatted_segment if @parent_singular
61
+ return formatted_segment if @parent_path.nil?
62
+ return "#{@parent_path}/#{formatted_segment}" if @parent_singular
62
63
 
63
- ":#{@parent_param || "#{@parent_identifiers.last.singularize}_id"}/#{formatted_segment}"
64
+ param = @parent_param || "#{@parent_identifiers.last.singularize}_id"
65
+ "#{@parent_path}/:#{param}/#{formatted_segment}"
64
66
  end
65
67
 
66
68
  def build_nested_resources(resource_path)
@@ -70,6 +72,7 @@ module Apiwork
70
72
 
71
73
  nested_options = {
72
74
  parent_identifiers: child_parent_identifiers,
75
+ parent_path: resource_path,
73
76
  parent_singular: @resource.singular,
74
77
  }
75
78
  nested_options[:parent_param] = @resource.param&.to_s || "#{@resource.name.to_s.singularize}_id" unless @resource.singular
@@ -4,6 +4,11 @@ module Apiwork
4
4
  module Introspection
5
5
  module Dump
6
6
  class Type
7
+ PRIMITIVE_TYPES = %i[
8
+ array binary boolean date datetime decimal enum float integer json
9
+ literal number object record string text time union unknown uuid
10
+ ].to_set.freeze
11
+
7
12
  def initialize(api_class)
8
13
  @api_class = api_class
9
14
  end
@@ -99,7 +104,11 @@ module Apiwork
99
104
  end
100
105
 
101
106
  def build_param(name, options, scope)
102
- reference = resolve_type_reference(options[:type], scope)
107
+ reference = if options[:custom_type]
108
+ resolve_type_reference(options[:custom_type], scope)
109
+ elsif options[:type] && !PRIMITIVE_TYPES.include?(options[:type])
110
+ resolve_type_reference(options[:type], scope)
111
+ end
103
112
 
104
113
  {
105
114
  reference:,
@@ -142,7 +151,7 @@ module Apiwork
142
151
  max: nil,
143
152
  min: nil,
144
153
  nullable: false,
145
- of: resolve_variant_of(variant, scope),
154
+ of: resolve_of(variant, scope),
146
155
  optional: false,
147
156
  partial: variant[:partial] == true,
148
157
  shape: build_nested_shape(variant[:shape]),
@@ -201,23 +210,41 @@ module Apiwork
201
210
  of = options[:of]
202
211
  return nil unless of
203
212
 
213
+ union = of.type == :union
214
+ union_shape = union && of.shape.is_a?(Apiwork::API::Union) ? of.shape : nil
204
215
  type_value = of.type
205
216
  scoped_name = resolve_scoped_type_name(type_value, scope)
206
- resolved_shape = of.shape ? build_nested_shape(of.shape) : {}
207
217
 
208
218
  result = {
219
+ as: nil,
220
+ default: nil,
221
+ deprecated: false,
222
+ description: nil,
223
+ discriminator: union ? of.discriminator : nil,
209
224
  enum: of.enum,
225
+ example: nil,
210
226
  format: of.format,
211
227
  max: of.max,
212
228
  min: of.min,
229
+ nullable: false,
230
+ of: nil,
231
+ optional: false,
232
+ partial: false,
213
233
  reference: scoped_name,
214
- shape: resolved_shape,
234
+ shape: union ? {} : resolve_of_shape(of),
235
+ tag: nil,
215
236
  type: scoped_name ? :reference : type_value,
237
+ value: nil,
238
+ variants: union_shape ? union_shape.variants.map { |variant| build_variant(variant, scope) } : [],
216
239
  }
217
240
  result[:of] = resolve_of({ of: of.inner }, scope) if of.type == :array && of.inner
218
241
  result
219
242
  end
220
243
 
244
+ def resolve_of_shape(of)
245
+ of.shape ? build_nested_shape(of.shape) : {}
246
+ end
247
+
221
248
  def resolve_variant_enum(variant, scope)
222
249
  return nil unless variant[:enum]
223
250
 
@@ -228,27 +255,6 @@ module Apiwork
228
255
  end
229
256
  end
230
257
 
231
- def resolve_variant_of(variant, scope)
232
- of = variant[:of]
233
- return nil unless of
234
-
235
- type_value = of.type
236
- scoped_name = resolve_scoped_type_name(type_value, scope)
237
- resolved_shape = of.shape ? build_nested_shape(of.shape) : {}
238
-
239
- result = {
240
- enum: of.enum,
241
- format: of.format,
242
- max: of.max,
243
- min: of.min,
244
- reference: scoped_name,
245
- shape: resolved_shape,
246
- type: scoped_name ? :reference : type_value,
247
- }
248
- result[:of] = resolve_variant_of({ of: of.inner }, scope) if of.type == :array && of.inner
249
- result
250
- end
251
-
252
258
  def build_enum(qualified_name, enum_definition)
253
259
  {
254
260
  deprecated: enum_definition.deprecated?,
@@ -20,6 +20,22 @@ module Apiwork
20
20
  # param.max # => 10 or nil
21
21
  # param.boundable? # => true
22
22
  class Array < Base
23
+ # @api public
24
+ # The default for this param.
25
+ #
26
+ # @return [Object, nil]
27
+ def default
28
+ @dump[:default]
29
+ end
30
+
31
+ # @api public
32
+ # The example for this param.
33
+ #
34
+ # @return [Object, nil]
35
+ def example
36
+ @dump[:example]
37
+ end
38
+
23
39
  # @api public
24
40
  # The of for this param.
25
41
  #
@@ -62,6 +78,14 @@ module Apiwork
62
78
  true
63
79
  end
64
80
 
81
+ # @api public
82
+ # Whether this param is concrete.
83
+ #
84
+ # @return [Boolean]
85
+ def concrete?
86
+ true
87
+ end
88
+
65
89
  # @api public
66
90
  # Whether this param is boundable.
67
91
  #
@@ -76,6 +100,8 @@ module Apiwork
76
100
  # @return [Hash]
77
101
  def to_h
78
102
  result = super
103
+ result[:default] = default
104
+ result[:example] = example
79
105
  result[:max] = max
80
106
  result[:min] = min
81
107
  result[:of] = of&.to_h
@@ -49,35 +49,19 @@ module Apiwork
49
49
  end
50
50
 
51
51
  # @api public
52
- # The example for this param.
53
- #
54
- # @return [Object, nil]
55
- def example
56
- @dump[:example]
57
- end
58
-
59
- # @api public
60
- # The default for this param.
52
+ # The tag for this param.
61
53
  #
62
- # @return [Object, nil]
63
- def default
64
- @dump[:default]
54
+ # @return [String, nil]
55
+ def tag
56
+ @dump[:tag]
65
57
  end
66
58
 
67
59
  # @api public
68
- # Whether this param has a default.
60
+ # Whether this param is concrete.
69
61
  #
70
62
  # @return [Boolean]
71
- def default?
72
- @dump.key?(:default)
73
- end
74
-
75
- # @api public
76
- # The tag for this param.
77
- #
78
- # @return [String, nil]
79
- def tag
80
- @dump[:tag]
63
+ def concrete?
64
+ false
81
65
  end
82
66
 
83
67
  # @api public
@@ -104,6 +88,14 @@ module Apiwork
104
88
  false
105
89
  end
106
90
 
91
+ # @api public
92
+ # Whether this param is a record.
93
+ #
94
+ # @return [Boolean]
95
+ def record?
96
+ false
97
+ end
98
+
107
99
  # @api public
108
100
  # Whether this param is a union.
109
101
  #
@@ -270,10 +262,8 @@ module Apiwork
270
262
  # @return [Hash]
271
263
  def to_h
272
264
  {
273
- default: default,
274
265
  deprecated: deprecated?,
275
266
  description: description,
276
- example: example,
277
267
  nullable: nullable?,
278
268
  optional: optional?,
279
269
  type: type,
@@ -20,6 +20,30 @@ module Apiwork
20
20
  # param.enum_reference? # => false
21
21
  # end
22
22
  class Binary < Base
23
+ # @api public
24
+ # The default for this param.
25
+ #
26
+ # @return [Object, nil]
27
+ def default
28
+ @dump[:default]
29
+ end
30
+
31
+ # @api public
32
+ # The example for this param.
33
+ #
34
+ # @return [Object, nil]
35
+ def example
36
+ @dump[:example]
37
+ end
38
+
39
+ # @api public
40
+ # Whether this param is concrete.
41
+ #
42
+ # @return [Boolean]
43
+ def concrete?
44
+ true
45
+ end
46
+
23
47
  # @api public
24
48
  # Whether this param is scalar.
25
49
  #
@@ -67,6 +91,18 @@ module Apiwork
67
91
  def formattable?
68
92
  false
69
93
  end
94
+
95
+ # @api public
96
+ # Converts this param to a hash.
97
+ #
98
+ # @return [Hash]
99
+ def to_h
100
+ result = super
101
+ result[:default] = default
102
+ result[:enum] = enum if enum?
103
+ result[:example] = example
104
+ result
105
+ end
70
106
  end
71
107
  end
72
108
  end