-
Notifications
You must be signed in to change notification settings - Fork 64
/
schema_cleaner.rb
86 lines (74 loc) · 2.66 KB
/
schema_cleaner.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# For Ruby 3.0+
require 'set'
require_relative 'hash_helper'
class << RSpec::OpenAPI::SchemaCleaner = Object.new
# Cleanup the properties, of component schemas, that exists in the base but not in the spec.
#
# @param [Hash] base
# @param [Hash] spec
def cleanup_components_schemas!(base, spec)
cleanup_hash!(base, spec, 'components.schemas.*')
cleanup_hash!(base, spec, 'components.schemas.*.properties.*')
end
# Cleanup specific elements that exists in the base but not in the spec
#
# @param [Hash] base
# @param [Hash] spec
def cleanup!(base, spec)
# cleanup URLs
cleanup_hash!(base, spec, 'paths.*')
# cleanup HTTP methods
cleanup_hash!(base, spec, 'paths.*.*')
# cleanup parameters
cleanup_array!(base, spec, 'paths.*.*.parameters', %w[name in])
# cleanup requestBody
cleanup_hash!(base, spec, 'paths.*.*.requestBody.content.application/json.schema.properties.*')
cleanup_hash!(base, spec, 'paths.*.*.requestBody.content.application/json.example.*')
# cleanup responses
cleanup_hash!(base, spec, 'paths.*.*.responses.*.content.application/json.schema.properties.*')
cleanup_hash!(base, spec, 'paths.*.*.responses.*.content.application/json.example.*')
base
end
private
def cleanup_array!(base, spec, selector, fields_for_identity = [])
marshal = lambda do |obj|
Marshal.dump(slice(obj, fields_for_identity))
end
RSpec::OpenAPI::HashHelper::matched_paths(base, selector).each do |paths|
target_array = base.dig(*paths)
spec_array = spec.dig(*paths)
unless target_array.is_a?(Array) && spec_array.is_a?(Array)
next
end
spec_identities = Set.new(spec_array.map(&marshal))
target_array.select! { |e| spec_identities.include?(marshal.call(e)) }
target_array.sort_by! { |param| fields_for_identity.map {|f| param[f] }.join('-') }
# Keep the last duplicate to produce the result stably
deduplicated = target_array.reverse.uniq { |param| slice(param, fields_for_identity) }.reverse
target_array.replace(deduplicated)
end
base
end
def cleanup_hash!(base, spec, selector)
RSpec::OpenAPI::HashHelper::matched_paths(base, selector).each do |paths|
exist_in_base = !base.dig(*paths).nil?
not_in_spec = spec.dig(*paths).nil?
if exist_in_base && not_in_spec
if paths.size == 1
base.delete(paths.last)
else
parent_node = base.dig(*paths[0..-2])
parent_node.delete(paths.last)
end
end
end
base
end
def slice(obj, fields_for_identity)
if fields_for_identity.any?
obj.slice(*fields_for_identity)
else
obj
end
end
end