diff --git a/lib/openapi_contracts/doc/parser.rb b/lib/openapi_contracts/doc/parser.rb index ea82697..a44da47 100644 --- a/lib/openapi_contracts/doc/parser.rb +++ b/lib/openapi_contracts/doc/parser.rb @@ -20,7 +20,7 @@ def parse(path = 'openapi.yaml') def parse_file(path, translate: true) schema = YAML.safe_load(File.read(path)) - translate ? translate_paths(schema, Pathname(path).parent) : schema + translate ? translate_paths!(schema, Pathname(path).parent) : schema end def join_partials(cwd, data) @@ -67,14 +67,17 @@ def merge_components data end - def translate_paths(data, cwd) - data.each_with_object({}) do |(key, val), m| - if val.is_a?(Hash) - m[key] = translate_paths(val, cwd) - elsif key == '$ref' && val !~ %r{^#/} - m[key] = json_pointer(cwd.join(val), '#/') - else - m[key] = val + def translate_paths!(data, cwd) + case data + when Array + data.each { |v| translate_paths!(v, cwd) } + when Hash + data.each_pair do |k, v| + if k == '$ref' && v !~ %r{^#/} + v.replace json_pointer(cwd.join(v), '#/') + else + translate_paths!(v, cwd) + end end end end diff --git a/spec/fixtures/openapi/components/schemas/Address.yaml b/spec/fixtures/openapi/components/schemas/Address.yaml new file mode 100644 index 0000000..e298f0f --- /dev/null +++ b/spec/fixtures/openapi/components/schemas/Address.yaml @@ -0,0 +1,6 @@ +type: object +properties: + street: + type: string + city: + type: string diff --git a/spec/fixtures/openapi/components/schemas/User.yaml b/spec/fixtures/openapi/components/schemas/User.yaml index 156c1d1..95e7af4 100644 --- a/spec/fixtures/openapi/components/schemas/User.yaml +++ b/spec/fixtures/openapi/components/schemas/User.yaml @@ -11,6 +11,10 @@ properties: name: type: string nullable: true + addresses: + type: array + oneOf: + - $ref: './Address.yaml' email: $ref: './Email.yaml' additionalProperties: false diff --git a/spec/integration/rspec_spec.rb b/spec/integration/rspec_spec.rb index e6eadbf..50adb1b 100644 --- a/spec/integration/rspec_spec.rb +++ b/spec/integration/rspec_spec.rb @@ -62,4 +62,16 @@ it { is_expected.to_not match_openapi_doc(doc) } end + + context 'when an attribute does match type oneOf' do + before { response_body[:data][:attributes][:addresses] = {street: 'Somestreet'} } + + it { is_expected.to_not match_openapi_doc(doc) } + end + + context 'when an attribute does not match type oneOf' do + before { response_body[:data][:attributes][:addresses] = {foo: 'bar'} } + + it { is_expected.to_not match_openapi_doc(doc) } + end end