verquest 0.6.3 → 0.7.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 +4 -4
- data/CHANGELOG.md +47 -0
- data/README.md +324 -51
- data/Rakefile +5 -0
- data/docs/rails.md +169 -0
- data/lib/verquest/base/condition_class_methods.rb +211 -0
- data/lib/verquest/base/private_class_methods.rb +34 -15
- data/lib/verquest/base/public_class_methods.rb +51 -1
- data/lib/verquest/base.rb +1 -0
- data/lib/verquest/conditions/branch.rb +111 -0
- data/lib/verquest/conditions/condition.rb +194 -0
- data/lib/verquest/conditions/conjunction.rb +39 -0
- data/lib/verquest/conditions/fragment_merge.rb +52 -0
- data/lib/verquest/conditions/property_merge.rb +47 -0
- data/lib/verquest/conditions/rule_set.rb +58 -0
- data/lib/verquest/conditions/rules/absent.rb +25 -0
- data/lib/verquest/conditions/rules/alternatives.rb +28 -0
- data/lib/verquest/conditions/rules/any.rb +27 -0
- data/lib/verquest/conditions/rules/equals.rb +22 -0
- data/lib/verquest/conditions/rules/names_rule.rb +23 -0
- data/lib/verquest/conditions/rules/none.rb +24 -0
- data/lib/verquest/conditions/rules/present.rb +22 -0
- data/lib/verquest/conditions/rules/property_rule.rb +48 -0
- data/lib/verquest/conditions/rules/satisfies.rb +22 -0
- data/lib/verquest/conditions/rules/value_in.rb +22 -0
- data/lib/verquest/conditions/rules.rb +17 -0
- data/lib/verquest/conditions.rb +36 -0
- data/lib/verquest/configuration.rb +19 -1
- data/lib/verquest/gem_version.rb +1 -1
- data/lib/verquest/helper_methods/conditional_properties.rb +126 -0
- data/lib/verquest/helper_methods/unnamed_one_of.rb +35 -0
- data/lib/verquest/properties/array.rb +15 -1
- data/lib/verquest/properties/base.rb +116 -10
- data/lib/verquest/properties/collection.rb +51 -18
- data/lib/verquest/properties/const.rb +5 -4
- data/lib/verquest/properties/enum.rb +1 -5
- data/lib/verquest/properties/field.rb +1 -0
- data/lib/verquest/properties/object.rb +38 -4
- data/lib/verquest/properties/one_of/discriminated_schema.rb +84 -0
- data/lib/verquest/properties/one_of.rb +86 -54
- data/lib/verquest/properties/reference.rb +49 -37
- data/lib/verquest/query/coercer.rb +165 -0
- data/lib/verquest/query/definition_check.rb +91 -0
- data/lib/verquest/query/parameters.rb +79 -0
- data/lib/verquest/query.rb +25 -0
- data/lib/verquest/transformer/collection.rb +32 -0
- data/lib/verquest/transformer/const_as_enum.rb +47 -0
- data/lib/verquest/transformer/layout.rb +83 -0
- data/lib/verquest/transformer/mapping_layout.rb +166 -0
- data/lib/verquest/transformer/one_of.rb +111 -0
- data/lib/verquest/transformer/path.rb +188 -0
- data/lib/verquest/transformer/plan.rb +183 -0
- data/lib/verquest/transformer/scope.rb +64 -0
- data/lib/verquest/transformer.rb +43 -880
- data/lib/verquest/version.rb +152 -79
- data/lib/verquest.rb +6 -0
- metadata +43 -8
data/lib/verquest/version.rb
CHANGED
|
@@ -20,6 +20,8 @@ module Verquest
|
|
|
20
20
|
# mapping = version.mapping
|
|
21
21
|
class Version
|
|
22
22
|
include HelperMethods::RequiredProperties
|
|
23
|
+
include HelperMethods::ConditionalProperties
|
|
24
|
+
include HelperMethods::UnnamedOneOf
|
|
23
25
|
|
|
24
26
|
# @!attribute [r] name
|
|
25
27
|
# @return [String] The name/identifier of the version (e.g., "2023-01")
|
|
@@ -41,7 +43,10 @@ module Verquest
|
|
|
41
43
|
#
|
|
42
44
|
# @!attribute [r] external_mapping
|
|
43
45
|
# @return [Hash] The mapping from internal attribute paths back to external paths
|
|
44
|
-
|
|
46
|
+
#
|
|
47
|
+
# @!attribute [r] location
|
|
48
|
+
# @return [Symbol] Where the params come from, `:body`, `:query` or `:path`
|
|
49
|
+
attr_reader :name, :properties, :schema, :validation_schema, :mapping, :transformer, :external_mapping, :location
|
|
45
50
|
|
|
46
51
|
# @!attribute [rw] schema_options
|
|
47
52
|
# @return [Hash] Additional JSON schema options for this version
|
|
@@ -53,11 +58,17 @@ module Verquest
|
|
|
53
58
|
# Initialize a new Version instance
|
|
54
59
|
#
|
|
55
60
|
# @param name [String] The name/identifier of the version
|
|
61
|
+
# @param location [Symbol] Where the params come from, `:body`, `:query` or `:path`
|
|
56
62
|
# @return [Version] A new Version instance
|
|
57
|
-
def initialize(name:)
|
|
63
|
+
def initialize(name:, location: :body)
|
|
58
64
|
@name = name.to_s
|
|
65
|
+
@location = location
|
|
59
66
|
@schema_options = {}
|
|
60
67
|
@properties = {}
|
|
68
|
+
@conditions = []
|
|
69
|
+
# Filled after the version is frozen, so it is created here; freeze is shallow
|
|
70
|
+
@validation_schemers = {}
|
|
71
|
+
@validation_schemers_lock = Mutex.new
|
|
61
72
|
end
|
|
62
73
|
|
|
63
74
|
# Add a property to this version
|
|
@@ -65,6 +76,7 @@ module Verquest
|
|
|
65
76
|
# @param property [Verquest::Properties::Base] The property to add
|
|
66
77
|
# @return [Verquest::Properties::Base] The added property
|
|
67
78
|
def add(property)
|
|
79
|
+
check_unnamed_one_of(property)
|
|
68
80
|
properties[property.name] = property
|
|
69
81
|
end
|
|
70
82
|
|
|
@@ -85,7 +97,17 @@ module Verquest
|
|
|
85
97
|
properties.key?(property_name.to_s)
|
|
86
98
|
end
|
|
87
99
|
|
|
88
|
-
#
|
|
100
|
+
# Returns the regular properties followed by the branch properties
|
|
101
|
+
#
|
|
102
|
+
# Stored when the version is prepared, because the version is frozen
|
|
103
|
+
# afterwards and `process` reads it on every request.
|
|
104
|
+
#
|
|
105
|
+
# @return [Hash<String, Verquest::Properties::Base>] All properties listed in the schema
|
|
106
|
+
def all_properties
|
|
107
|
+
@all_properties || super
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Copy properties and conditions from another version
|
|
89
111
|
#
|
|
90
112
|
# @param version [Verquest::Version] The version to copy properties from
|
|
91
113
|
# @param exclude_properties [Array<Symbol>] Names of properties to not copy
|
|
@@ -99,6 +121,8 @@ module Verquest
|
|
|
99
121
|
|
|
100
122
|
add(property)
|
|
101
123
|
end
|
|
124
|
+
|
|
125
|
+
version.conditions.each { |condition| add_condition(condition) }
|
|
102
126
|
end
|
|
103
127
|
|
|
104
128
|
# Prepare this version by generating schema and creating transformer
|
|
@@ -112,21 +136,22 @@ module Verquest
|
|
|
112
136
|
end
|
|
113
137
|
|
|
114
138
|
schema_options.delete_if { |_, v| v.nil? }
|
|
139
|
+
@all_properties = all_properties
|
|
115
140
|
|
|
116
141
|
if combination?
|
|
117
142
|
prepare_combination_schema
|
|
118
143
|
prepare_combination_validation_schema
|
|
119
144
|
prepare_combination_mapping
|
|
120
145
|
prepare_combination_external_mapping
|
|
121
|
-
@transformer = Transformer.new(mapping: mapping, discriminator: combination_discriminator)
|
|
122
146
|
else
|
|
123
147
|
prepare_schema
|
|
124
148
|
prepare_validation_schema
|
|
125
149
|
prepare_mapping
|
|
126
150
|
prepare_external_mapping
|
|
127
|
-
@transformer = Transformer.new(mapping: mapping)
|
|
128
151
|
end
|
|
129
152
|
|
|
153
|
+
prepare_parameters if parameters?
|
|
154
|
+
@transformer = Transformer.new(layout: transformer_layout)
|
|
130
155
|
freeze
|
|
131
156
|
end
|
|
132
157
|
|
|
@@ -167,13 +192,7 @@ module Verquest
|
|
|
167
192
|
# @param params [Hash] The request parameters to validate
|
|
168
193
|
# @return [Array<Hash>] An array of validation error details, or empty if valid
|
|
169
194
|
def validate_params(params:)
|
|
170
|
-
|
|
171
|
-
validation_schema,
|
|
172
|
-
meta_schema: Verquest.configuration.json_schema_uri,
|
|
173
|
-
insert_property_defaults: Verquest.configuration.insert_property_defaults
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
schemer.validate(params).map do |error|
|
|
195
|
+
validation_schemer.validate(params).map do |error|
|
|
177
196
|
{
|
|
178
197
|
pointer: error["data_pointer"],
|
|
179
198
|
type: error["type"],
|
|
@@ -185,17 +204,48 @@ module Verquest
|
|
|
185
204
|
|
|
186
205
|
# Get the mapping for a specific property
|
|
187
206
|
#
|
|
188
|
-
# @param property [Symbol, String] The property name
|
|
207
|
+
# @param property [Symbol, String] The property name (regular or declared in a condition branch)
|
|
189
208
|
# @return [Hash] The mapping for the property
|
|
190
209
|
# @raise [PropertyNotFoundError] If the property doesn't exist
|
|
191
210
|
def mapping_for(property)
|
|
192
|
-
raise PropertyNotFoundError.new("Property '#{property}' is not defined on '#{name}'") unless has?(property)
|
|
193
|
-
|
|
194
211
|
{}.tap do |mapping|
|
|
195
|
-
|
|
212
|
+
fetch_property(property).mapping(key_prefix: [], value_prefix: [], mapping: mapping, version: name)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Get a property by name
|
|
217
|
+
#
|
|
218
|
+
# @param property [Symbol, String] The property name (regular or declared in a condition branch)
|
|
219
|
+
# @return [Verquest::Properties::Base] The property
|
|
220
|
+
# @raise [PropertyNotFoundError] If the property doesn't exist
|
|
221
|
+
def fetch_property(property)
|
|
222
|
+
all_properties.fetch(property.to_s) do
|
|
223
|
+
raise PropertyNotFoundError.new("Property '#{property}' is not defined on '#{name}'")
|
|
196
224
|
end
|
|
197
225
|
end
|
|
198
226
|
|
|
227
|
+
# Check if this version reads its params from the query string or the path
|
|
228
|
+
#
|
|
229
|
+
# @return [Boolean] true for a query or path version
|
|
230
|
+
def parameters?
|
|
231
|
+
location != :body
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Converts query or path strings to the types the validation schema expects
|
|
235
|
+
#
|
|
236
|
+
# @param params [Hash] The parsed request parameters
|
|
237
|
+
# @return [Hash] Converted params for a query or path version, the same params otherwise
|
|
238
|
+
def coerce_params(params)
|
|
239
|
+
parameters? ? query_coercer.call(params) : params
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Returns OpenAPI parameter objects for this query or path version
|
|
243
|
+
#
|
|
244
|
+
# @return [Array<Hash>] A new array of parameter objects on each call
|
|
245
|
+
def parameters
|
|
246
|
+
Query::Parameters.new(schema: validation_schema, options: query_options, location:).call
|
|
247
|
+
end
|
|
248
|
+
|
|
199
249
|
# Map request parameters to internal representation using the transformer
|
|
200
250
|
#
|
|
201
251
|
# @param params [Hash] The request parameters to map
|
|
@@ -232,19 +282,55 @@ module Verquest
|
|
|
232
282
|
nested_one_of_count > 1
|
|
233
283
|
end
|
|
234
284
|
|
|
235
|
-
# Returns the count of nested oneOf properties
|
|
285
|
+
# Returns the count of nested oneOf properties
|
|
286
|
+
#
|
|
287
|
+
# Not memoized, because the version is frozen once it is prepared.
|
|
236
288
|
#
|
|
237
289
|
# @return [Integer] Number of nested oneOf properties
|
|
238
290
|
def nested_one_of_count
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
@_nested_one_of_count = properties.values.count do |p|
|
|
291
|
+
properties.values.count do |p|
|
|
242
292
|
p.is_a?(Verquest::Properties::OneOf) && !p.name.nil?
|
|
243
293
|
end
|
|
244
294
|
end
|
|
245
295
|
|
|
246
296
|
private
|
|
247
297
|
|
|
298
|
+
# @return [Verquest::Query::Coercer, nil] The coercer of a query or path version
|
|
299
|
+
attr_reader :query_coercer
|
|
300
|
+
|
|
301
|
+
# @return [Hash{Array<String> => Hash}, nil] The parameter options of each property path of a query or path version
|
|
302
|
+
attr_reader :query_options
|
|
303
|
+
|
|
304
|
+
# Checks a query or path version and builds its coercer
|
|
305
|
+
#
|
|
306
|
+
# @return [void]
|
|
307
|
+
# @raise [Verquest::DefinitionError] If the version uses a shape its location can't express
|
|
308
|
+
def prepare_parameters
|
|
309
|
+
Query::DefinitionCheck.new(self).call
|
|
310
|
+
|
|
311
|
+
@query_options = all_properties.each_value.with_object({}) do |property, options|
|
|
312
|
+
options.merge!(property.query_options(prefix: [], version: name))
|
|
313
|
+
end.freeze
|
|
314
|
+
explodes = query_options.filter_map { |path, options| [path, options[:explode]] if options.key?(:explode) }.to_h
|
|
315
|
+
@query_coercer = Query::Coercer.new(schema: validation_schema, explodes:)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# Returns the compiled validation schema for the current configuration
|
|
319
|
+
#
|
|
320
|
+
# Compiling is much slower than validating, so each configuration is
|
|
321
|
+
# compiled once and reused. The lock keeps threads from compiling at the
|
|
322
|
+
# same time.
|
|
323
|
+
#
|
|
324
|
+
# @return [JSONSchemer::Schema] The compiled validation schema
|
|
325
|
+
def validation_schemer
|
|
326
|
+
configuration = Verquest.configuration
|
|
327
|
+
key = [configuration.json_schema_uri, configuration.insert_property_defaults]
|
|
328
|
+
|
|
329
|
+
@validation_schemers_lock.synchronize do
|
|
330
|
+
@validation_schemers[key] ||= JSONSchemer.schema(validation_schema, meta_schema: key[0], insert_property_defaults: key[1])
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
248
334
|
# Generates the JSON schema for this version
|
|
249
335
|
#
|
|
250
336
|
# Creates a schema object with type, description, required properties,
|
|
@@ -256,10 +342,11 @@ module Verquest
|
|
|
256
342
|
@schema = {
|
|
257
343
|
"type" => "object",
|
|
258
344
|
"required" => required_properties,
|
|
259
|
-
"properties" =>
|
|
345
|
+
"properties" => all_properties.transform_values { |property| property.to_schema[property.name] }
|
|
260
346
|
}.merge(schema_options).tap do |schema|
|
|
261
347
|
schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
|
|
262
348
|
schema["description"] = description if description
|
|
349
|
+
add_conditions(schema, documentation: true)
|
|
263
350
|
end.freeze
|
|
264
351
|
end
|
|
265
352
|
|
|
@@ -269,7 +356,10 @@ module Verquest
|
|
|
269
356
|
# property since it represents the entire request structure.
|
|
270
357
|
#
|
|
271
358
|
# @return [Hash] The schema from the oneOf property
|
|
359
|
+
# @raise [ArgumentError] If the version also has conditions
|
|
272
360
|
def prepare_combination_schema
|
|
361
|
+
raise ArgumentError, "Conditions can not be declared next to a root-level one_of" if conditions.any?
|
|
362
|
+
|
|
273
363
|
@schema = properties.values.first.to_schema
|
|
274
364
|
end
|
|
275
365
|
|
|
@@ -283,10 +373,11 @@ module Verquest
|
|
|
283
373
|
@validation_schema = {
|
|
284
374
|
"type" => "object",
|
|
285
375
|
"required" => required_properties,
|
|
286
|
-
"properties" =>
|
|
376
|
+
"properties" => all_properties.transform_values { |property| property.to_validation_schema(version: name)[property.name] }
|
|
287
377
|
}.merge(schema_options).tap do |schema|
|
|
288
378
|
schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
|
|
289
379
|
schema["description"] = description if description
|
|
380
|
+
add_conditions(schema)
|
|
290
381
|
end.freeze
|
|
291
382
|
end
|
|
292
383
|
|
|
@@ -312,8 +403,8 @@ module Verquest
|
|
|
312
403
|
# @raise [MappingError] If duplicate mappings are detected
|
|
313
404
|
def prepare_mapping
|
|
314
405
|
# Separate oneOf properties from regular properties
|
|
315
|
-
one_of_properties =
|
|
316
|
-
regular_properties =
|
|
406
|
+
one_of_properties = all_properties.values.select { |p| p.is_a?(Verquest::Properties::OneOf) }
|
|
407
|
+
regular_properties = all_properties.values.reject { |p| p.is_a?(Verquest::Properties::OneOf) }
|
|
317
408
|
|
|
318
409
|
if one_of_properties.size == 1
|
|
319
410
|
prepare_single_nested_one_of_mapping(one_of_properties.first, regular_properties)
|
|
@@ -335,6 +426,7 @@ module Verquest
|
|
|
335
426
|
regular_properties.each do |property|
|
|
336
427
|
property.mapping(key_prefix: [], value_prefix: [], mapping: regular_mapping, version: name)
|
|
337
428
|
end
|
|
429
|
+
return prepare_multiple_nested_one_of_mapping([one_of_property], regular_properties) if regular_mapping.key?("_oneOfs")
|
|
338
430
|
|
|
339
431
|
# Collect oneOf property mappings
|
|
340
432
|
one_of_mapping = {}
|
|
@@ -344,12 +436,12 @@ module Verquest
|
|
|
344
436
|
@mapping = {}
|
|
345
437
|
|
|
346
438
|
# Preserve metadata keys
|
|
347
|
-
|
|
439
|
+
Transformer::METADATA_KEYS.each do |metadata_key|
|
|
348
440
|
@mapping[metadata_key] = one_of_mapping[metadata_key] if one_of_mapping.key?(metadata_key)
|
|
349
441
|
end
|
|
350
442
|
|
|
351
443
|
one_of_mapping.each do |discriminator_value, variant_mapping|
|
|
352
|
-
next if
|
|
444
|
+
next if Transformer::METADATA_KEYS.include?(discriminator_value)
|
|
353
445
|
|
|
354
446
|
@mapping[discriminator_value] = regular_mapping.merge(variant_mapping)
|
|
355
447
|
end
|
|
@@ -368,8 +460,8 @@ module Verquest
|
|
|
368
460
|
property.mapping(key_prefix: [], value_prefix: [], mapping: @mapping, version: name)
|
|
369
461
|
end
|
|
370
462
|
|
|
371
|
-
# Collect each oneOf's mapping into _oneOfs array
|
|
372
|
-
@mapping["_oneOfs"] = one_of_properties.map do |one_of_property|
|
|
463
|
+
# Collect each oneOf's mapping into _oneOfs array, after the ones nested in objects
|
|
464
|
+
@mapping["_oneOfs"] = @mapping.fetch("_oneOfs", []) + one_of_properties.map do |one_of_property|
|
|
373
465
|
one_of_mapping = {}
|
|
374
466
|
one_of_property.mapping(key_prefix: [], value_prefix: [], mapping: one_of_mapping, version: name)
|
|
375
467
|
one_of_mapping
|
|
@@ -387,7 +479,7 @@ module Verquest
|
|
|
387
479
|
end
|
|
388
480
|
|
|
389
481
|
seen = Set.new
|
|
390
|
-
duplicates = mapping.values.select { |v| !seen.add?(v) }
|
|
482
|
+
duplicates = mapping.except(*Transformer::METADATA_KEYS).values.select { |v| !seen.add?(v) }
|
|
391
483
|
if duplicates.any?
|
|
392
484
|
raise MappingError.new("Mapping must be unique. Found duplicates in version '#{name}': #{duplicates.uniq.join(", ")}")
|
|
393
485
|
end
|
|
@@ -406,53 +498,39 @@ module Verquest
|
|
|
406
498
|
# paths and values are the corresponding external schema paths
|
|
407
499
|
# @see #prepare_mapping
|
|
408
500
|
def prepare_external_mapping
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
invert_single_one_of_mapping
|
|
501
|
+
# A single top-level oneOf is keyed by variant; any other mapping is a path mapping, with oneOfs in _oneOfs.
|
|
502
|
+
@external_mapping = if has_nested_one_of? && !mapping.key?("_oneOfs")
|
|
503
|
+
invert_one_of_mapping(mapping)
|
|
413
504
|
else
|
|
414
|
-
mapping
|
|
415
|
-
end
|
|
416
|
-
end
|
|
417
|
-
|
|
418
|
-
# Inverts mapping for single nested oneOf
|
|
419
|
-
#
|
|
420
|
-
# @return [Hash] The inverted mapping
|
|
421
|
-
def invert_single_one_of_mapping
|
|
422
|
-
mapping.each_with_object({}) do |(key, value), result|
|
|
423
|
-
result[key] = if key.start_with?("_")
|
|
424
|
-
value
|
|
425
|
-
else
|
|
426
|
-
value.invert
|
|
427
|
-
end
|
|
505
|
+
invert_path_mapping(mapping)
|
|
428
506
|
end.freeze
|
|
429
507
|
end
|
|
430
508
|
|
|
431
|
-
# Inverts mapping
|
|
509
|
+
# Inverts the source and target pairs of a mapping, and the oneOfs in its `_oneOfs`
|
|
510
|
+
#
|
|
511
|
+
# A path mapping holds only pairs and `_oneOfs`; a oneOf's other metadata
|
|
512
|
+
# sits in its own mapping, which {#invert_one_of_mapping} keeps as it is.
|
|
432
513
|
#
|
|
514
|
+
# @param path_mapping [Hash] The mapping of source paths to target paths
|
|
433
515
|
# @return [Hash] The inverted mapping
|
|
434
|
-
def
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
mapping.each do |key, value|
|
|
516
|
+
def invert_path_mapping(path_mapping)
|
|
517
|
+
path_mapping.each_with_object({}) do |(key, value), result|
|
|
438
518
|
if key == "_oneOfs"
|
|
439
|
-
result[
|
|
440
|
-
one_of_mapping.each_with_object({}) do |(k, v), inverted|
|
|
441
|
-
inverted[k] = if k.start_with?("_")
|
|
442
|
-
v
|
|
443
|
-
else
|
|
444
|
-
v.invert
|
|
445
|
-
end
|
|
446
|
-
end
|
|
447
|
-
end
|
|
448
|
-
elsif key.start_with?("_")
|
|
449
|
-
result[key] = value
|
|
519
|
+
result[key] = value.map { |one_of_mapping| invert_one_of_mapping(one_of_mapping) }
|
|
450
520
|
else
|
|
451
|
-
result[value] = key
|
|
521
|
+
result[value] = key
|
|
452
522
|
end
|
|
453
523
|
end
|
|
524
|
+
end
|
|
454
525
|
|
|
455
|
-
|
|
526
|
+
# Inverts each variant mapping of a oneOf mapping, keeping its metadata
|
|
527
|
+
#
|
|
528
|
+
# @param one_of_mapping [Hash] The oneOf mapping (variant name => variant mapping, plus metadata)
|
|
529
|
+
# @return [Hash] The oneOf mapping with each variant mapping inverted
|
|
530
|
+
def invert_one_of_mapping(one_of_mapping)
|
|
531
|
+
one_of_mapping.to_h do |key, value|
|
|
532
|
+
[key, Transformer::METADATA_KEYS.include?(key) ? value : invert_path_mapping(value)]
|
|
533
|
+
end
|
|
456
534
|
end
|
|
457
535
|
|
|
458
536
|
# Prepares the parameter mapping for combination schemas (oneOf)
|
|
@@ -473,23 +551,18 @@ module Verquest
|
|
|
473
551
|
#
|
|
474
552
|
# @return [Hash] The frozen inverted mapping for each discriminator value
|
|
475
553
|
def prepare_combination_external_mapping
|
|
476
|
-
@external_mapping = mapping.
|
|
477
|
-
# Skip metadata keys, only invert variant mapping hashes
|
|
478
|
-
result[key] = if key.start_with?("_")
|
|
479
|
-
value
|
|
480
|
-
else
|
|
481
|
-
value.invert
|
|
482
|
-
end
|
|
483
|
-
end.freeze
|
|
554
|
+
@external_mapping = invert_one_of_mapping(mapping).freeze
|
|
484
555
|
end
|
|
485
556
|
|
|
486
|
-
# Returns the
|
|
557
|
+
# Returns the full paths of this version's properties for the transformer
|
|
487
558
|
#
|
|
488
|
-
# @return [
|
|
489
|
-
def
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
559
|
+
# @return [Verquest::Transformer::Layout] The layout
|
|
560
|
+
def transformer_layout
|
|
561
|
+
Transformer::Layout.new.tap do |layout|
|
|
562
|
+
all_properties.each_value do |property|
|
|
563
|
+
property.layout(key_prefix: [], value_prefix: [], layout:, version: name)
|
|
564
|
+
end
|
|
565
|
+
end
|
|
493
566
|
end
|
|
494
567
|
end
|
|
495
568
|
end
|
data/lib/verquest.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "zeitwerk"
|
|
4
4
|
require "json_schemer"
|
|
5
|
+
require "digest"
|
|
6
|
+
require "json"
|
|
5
7
|
|
|
6
8
|
require_relative "verquest/gem_version"
|
|
7
9
|
|
|
@@ -66,6 +68,10 @@ module Verquest
|
|
|
66
68
|
# @api public
|
|
67
69
|
MappingError = Class.new(Verquest::Error)
|
|
68
70
|
|
|
71
|
+
# Error raised when a request definition uses a shape its location can't express
|
|
72
|
+
# @api public
|
|
73
|
+
DefinitionError = Class.new(Verquest::Error)
|
|
74
|
+
|
|
69
75
|
# Error raised when parameters do not match the expected schema
|
|
70
76
|
# @api public
|
|
71
77
|
InvalidParamsError = Class.new(Verquest::Error) do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: verquest
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Petr Hlavicka
|
|
@@ -37,10 +37,10 @@ dependencies:
|
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '2.4'
|
|
40
|
-
description: Verquest
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
OpenAPI.
|
|
40
|
+
description: Verquest describes API request bodies, query strings and path parameters
|
|
41
|
+
with a Ruby DSL, one definition per API version. It validates params against JSON
|
|
42
|
+
Schema, maps them from your public API structure to your internal one, and generates
|
|
43
|
+
JSON Schema components and OpenAPI parameters for documentation tools like rswag.
|
|
44
44
|
email:
|
|
45
45
|
- yes@petr.codes
|
|
46
46
|
executables: []
|
|
@@ -54,14 +54,36 @@ files:
|
|
|
54
54
|
- LICENSE.txt
|
|
55
55
|
- README.md
|
|
56
56
|
- Rakefile
|
|
57
|
+
- docs/rails.md
|
|
57
58
|
- lib/verquest.rb
|
|
58
59
|
- lib/verquest/base.rb
|
|
60
|
+
- lib/verquest/base/condition_class_methods.rb
|
|
59
61
|
- lib/verquest/base/helper_class_methods.rb
|
|
60
62
|
- lib/verquest/base/private_class_methods.rb
|
|
61
63
|
- lib/verquest/base/public_class_methods.rb
|
|
64
|
+
- lib/verquest/conditions.rb
|
|
65
|
+
- lib/verquest/conditions/branch.rb
|
|
66
|
+
- lib/verquest/conditions/condition.rb
|
|
67
|
+
- lib/verquest/conditions/conjunction.rb
|
|
68
|
+
- lib/verquest/conditions/fragment_merge.rb
|
|
69
|
+
- lib/verquest/conditions/property_merge.rb
|
|
70
|
+
- lib/verquest/conditions/rule_set.rb
|
|
71
|
+
- lib/verquest/conditions/rules.rb
|
|
72
|
+
- lib/verquest/conditions/rules/absent.rb
|
|
73
|
+
- lib/verquest/conditions/rules/alternatives.rb
|
|
74
|
+
- lib/verquest/conditions/rules/any.rb
|
|
75
|
+
- lib/verquest/conditions/rules/equals.rb
|
|
76
|
+
- lib/verquest/conditions/rules/names_rule.rb
|
|
77
|
+
- lib/verquest/conditions/rules/none.rb
|
|
78
|
+
- lib/verquest/conditions/rules/present.rb
|
|
79
|
+
- lib/verquest/conditions/rules/property_rule.rb
|
|
80
|
+
- lib/verquest/conditions/rules/satisfies.rb
|
|
81
|
+
- lib/verquest/conditions/rules/value_in.rb
|
|
62
82
|
- lib/verquest/configuration.rb
|
|
63
83
|
- lib/verquest/gem_version.rb
|
|
84
|
+
- lib/verquest/helper_methods/conditional_properties.rb
|
|
64
85
|
- lib/verquest/helper_methods/required_properties.rb
|
|
86
|
+
- lib/verquest/helper_methods/unnamed_one_of.rb
|
|
65
87
|
- lib/verquest/properties.rb
|
|
66
88
|
- lib/verquest/properties/array.rb
|
|
67
89
|
- lib/verquest/properties/base.rb
|
|
@@ -71,9 +93,22 @@ files:
|
|
|
71
93
|
- lib/verquest/properties/field.rb
|
|
72
94
|
- lib/verquest/properties/object.rb
|
|
73
95
|
- lib/verquest/properties/one_of.rb
|
|
96
|
+
- lib/verquest/properties/one_of/discriminated_schema.rb
|
|
74
97
|
- lib/verquest/properties/reference.rb
|
|
98
|
+
- lib/verquest/query.rb
|
|
99
|
+
- lib/verquest/query/coercer.rb
|
|
100
|
+
- lib/verquest/query/definition_check.rb
|
|
101
|
+
- lib/verquest/query/parameters.rb
|
|
75
102
|
- lib/verquest/result.rb
|
|
76
103
|
- lib/verquest/transformer.rb
|
|
104
|
+
- lib/verquest/transformer/collection.rb
|
|
105
|
+
- lib/verquest/transformer/const_as_enum.rb
|
|
106
|
+
- lib/verquest/transformer/layout.rb
|
|
107
|
+
- lib/verquest/transformer/mapping_layout.rb
|
|
108
|
+
- lib/verquest/transformer/one_of.rb
|
|
109
|
+
- lib/verquest/transformer/path.rb
|
|
110
|
+
- lib/verquest/transformer/plan.rb
|
|
111
|
+
- lib/verquest/transformer/scope.rb
|
|
77
112
|
- lib/verquest/version.rb
|
|
78
113
|
- lib/verquest/version_resolver.rb
|
|
79
114
|
- lib/verquest/versions.rb
|
|
@@ -98,8 +133,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
98
133
|
- !ruby/object:Gem::Version
|
|
99
134
|
version: '0'
|
|
100
135
|
requirements: []
|
|
101
|
-
rubygems_version: 3.6.
|
|
136
|
+
rubygems_version: 3.6.9
|
|
102
137
|
specification_version: 4
|
|
103
|
-
summary:
|
|
104
|
-
|
|
138
|
+
summary: Versioned API request definitions with JSON Schema validation, mapping and
|
|
139
|
+
OpenAPI output
|
|
105
140
|
test_files: []
|