openapi3_parser 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/.travis.yml +3 -5
- data/CHANGELOG.md +7 -0
- data/README.md +2 -2
- data/TODO.md +9 -2
- data/lib/openapi3_parser/context/pointer.rb +2 -0
- data/lib/openapi3_parser/document.rb +54 -18
- data/lib/openapi3_parser/markdown.rb +15 -0
- data/lib/openapi3_parser/{nodes → node}/array.rb +1 -1
- data/lib/openapi3_parser/{nodes → node}/callback.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/components.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/contact.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/discriminator.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/encoding.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/example.rb +7 -4
- data/lib/openapi3_parser/{nodes → node}/external_documentation.rb +7 -4
- data/lib/openapi3_parser/{nodes → node}/header.rb +4 -5
- data/lib/openapi3_parser/{nodes → node}/info.rb +9 -6
- data/lib/openapi3_parser/{nodes → node}/license.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/link.rb +7 -4
- data/lib/openapi3_parser/node/map.rb +1 -1
- data/lib/openapi3_parser/{nodes → node}/media_type.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/oauth_flow.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/oauth_flows.rb +2 -4
- data/lib/openapi3_parser/node/object.rb +11 -1
- data/lib/openapi3_parser/{nodes → node}/openapi.rb +6 -8
- data/lib/openapi3_parser/{nodes → node}/operation.rb +11 -8
- data/lib/openapi3_parser/{nodes → node}/parameter.rb +3 -4
- data/lib/openapi3_parser/node/parameter_like.rb +70 -0
- data/lib/openapi3_parser/{nodes → node}/path_item.rb +9 -6
- data/lib/openapi3_parser/{nodes → node}/paths.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/request_body.rb +7 -4
- data/lib/openapi3_parser/{nodes → node}/response.rb +7 -4
- data/lib/openapi3_parser/{nodes → node}/responses.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/schema.rb +12 -9
- data/lib/openapi3_parser/{nodes → node}/security_requirement.rb +2 -4
- data/lib/openapi3_parser/{nodes → node}/security_scheme.rb +7 -5
- data/lib/openapi3_parser/{nodes → node}/server.rb +7 -4
- data/lib/openapi3_parser/{nodes → node}/server_variable.rb +8 -5
- data/lib/openapi3_parser/{nodes → node}/tag.rb +7 -4
- data/lib/openapi3_parser/{nodes → node}/xml.rb +2 -4
- data/lib/openapi3_parser/node_factories/array.rb +10 -4
- data/lib/openapi3_parser/node_factories/callback.rb +2 -2
- data/lib/openapi3_parser/node_factories/components.rb +5 -3
- data/lib/openapi3_parser/node_factories/contact.rb +10 -4
- data/lib/openapi3_parser/node_factories/discriminator.rb +2 -2
- data/lib/openapi3_parser/node_factories/encoding.rb +7 -3
- data/lib/openapi3_parser/node_factories/example.rb +8 -3
- data/lib/openapi3_parser/node_factories/external_documentation.rb +7 -3
- data/lib/openapi3_parser/node_factories/header.rb +2 -2
- data/lib/openapi3_parser/node_factories/info.rb +6 -3
- data/lib/openapi3_parser/node_factories/license.rb +6 -3
- data/lib/openapi3_parser/node_factories/link.rb +4 -2
- data/lib/openapi3_parser/node_factories/map.rb +12 -4
- data/lib/openapi3_parser/node_factories/media_type.rb +36 -5
- data/lib/openapi3_parser/node_factories/oauth_flow.rb +2 -2
- data/lib/openapi3_parser/node_factories/oauth_flows.rb +2 -2
- data/lib/openapi3_parser/node_factories/openapi.rb +13 -3
- data/lib/openapi3_parser/node_factories/operation.rb +11 -3
- data/lib/openapi3_parser/node_factories/parameter.rb +28 -3
- data/lib/openapi3_parser/node_factories/parameter/parameter_like.rb +9 -5
- data/lib/openapi3_parser/node_factories/path_item.rb +26 -7
- data/lib/openapi3_parser/node_factories/paths.rb +51 -2
- data/lib/openapi3_parser/node_factories/reference.rb +4 -0
- data/lib/openapi3_parser/node_factories/request_body.rb +32 -3
- data/lib/openapi3_parser/node_factories/response.rb +24 -4
- data/lib/openapi3_parser/node_factories/responses.rb +28 -2
- data/lib/openapi3_parser/node_factories/schema.rb +17 -3
- data/lib/openapi3_parser/node_factories/security_requirement.rb +2 -2
- data/lib/openapi3_parser/node_factories/security_scheme.rb +2 -2
- data/lib/openapi3_parser/node_factories/server.rb +2 -2
- data/lib/openapi3_parser/node_factories/server_variable.rb +2 -2
- data/lib/openapi3_parser/node_factories/tag.rb +2 -2
- data/lib/openapi3_parser/node_factories/xml.rb +6 -3
- data/lib/openapi3_parser/node_factory.rb +10 -4
- data/lib/openapi3_parser/node_factory/fields/reference.rb +4 -0
- data/lib/openapi3_parser/node_factory/map.rb +10 -0
- data/lib/openapi3_parser/node_factory/object.rb +29 -0
- data/lib/openapi3_parser/node_factory/object/validator.rb +69 -6
- data/lib/openapi3_parser/source/reference.rb +2 -0
- data/lib/openapi3_parser/source/reference_resolver.rb +5 -1
- data/lib/openapi3_parser/validators/absolute_uri.rb +14 -0
- data/lib/openapi3_parser/validators/component_keys.rb +17 -0
- data/lib/openapi3_parser/validators/duplicate_parameters.rb +30 -0
- data/lib/openapi3_parser/validators/email.rb +23 -0
- data/lib/openapi3_parser/validators/media_type.rb +20 -0
- data/lib/openapi3_parser/validators/url.rb +18 -0
- data/lib/openapi3_parser/version.rb +1 -1
- data/openapi3_parser.gemspec +5 -2
- metadata +70 -36
- data/lib/openapi3_parser/nodes/map.rb +0 -17
- data/lib/openapi3_parser/nodes/parameter/parameter_like.rb +0 -67
@@ -3,7 +3,7 @@
|
|
3
3
|
require "openapi3_parser/context"
|
4
4
|
require "openapi3_parser/error"
|
5
5
|
require "openapi3_parser/node_factory/map"
|
6
|
-
require "openapi3_parser/
|
6
|
+
require "openapi3_parser/node/map"
|
7
7
|
require "openapi3_parser/validation/error"
|
8
8
|
require "openapi3_parser/validation/error_collection"
|
9
9
|
|
@@ -12,24 +12,28 @@ module Openapi3Parser
|
|
12
12
|
class Map
|
13
13
|
include NodeFactory::Map
|
14
14
|
|
15
|
+
# rubocop:disable Metrics/ParameterLists
|
15
16
|
def initialize(
|
16
17
|
context,
|
17
18
|
key_input_type: String,
|
18
19
|
value_input_type: nil,
|
19
20
|
value_factory: nil,
|
20
|
-
validate: nil
|
21
|
+
validate: nil,
|
22
|
+
default: {}
|
21
23
|
)
|
22
24
|
@given_key_input_type = key_input_type
|
23
25
|
@given_value_input_type = value_input_type
|
24
26
|
@given_value_factory = value_factory
|
25
27
|
@given_validate = validate
|
28
|
+
@given_default = default
|
26
29
|
super(context)
|
27
30
|
end
|
31
|
+
# rubocop:enable Metrics/ParameterLists
|
28
32
|
|
29
33
|
private
|
30
34
|
|
31
35
|
attr_reader :given_key_input_type, :given_value_input_type,
|
32
|
-
:given_value_factory, :given_validate
|
36
|
+
:given_value_factory, :given_validate, :given_default
|
33
37
|
|
34
38
|
def process_input(input)
|
35
39
|
input.each_with_object({}) do |(key, value), memo|
|
@@ -68,7 +72,7 @@ module Openapi3Parser
|
|
68
72
|
end
|
69
73
|
|
70
74
|
def build_map(data, context)
|
71
|
-
|
75
|
+
Node::Map.new(data, context)
|
72
76
|
end
|
73
77
|
|
74
78
|
def value_factory?
|
@@ -107,6 +111,10 @@ module Openapi3Parser
|
|
107
111
|
return unless type
|
108
112
|
"Expected #{type}" unless value.is_a?(type)
|
109
113
|
end
|
114
|
+
|
115
|
+
def default
|
116
|
+
given_default
|
117
|
+
end
|
110
118
|
end
|
111
119
|
end
|
112
120
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "openapi3_parser/
|
3
|
+
require "openapi3_parser/node/media_type"
|
4
4
|
require "openapi3_parser/node_factory/object"
|
5
5
|
require "openapi3_parser/node_factory/optional_reference"
|
6
6
|
require "openapi3_parser/node_factories/map"
|
@@ -14,15 +14,18 @@ module Openapi3Parser
|
|
14
14
|
include NodeFactory::Object
|
15
15
|
|
16
16
|
allow_extensions
|
17
|
+
|
17
18
|
field "schema", factory: :schema_factory
|
18
19
|
field "example"
|
19
20
|
field "examples", factory: :examples_factory
|
20
21
|
field "encoding", factory: :encoding_factory
|
21
22
|
|
23
|
+
mutually_exclusive "example", "examples"
|
24
|
+
|
22
25
|
private
|
23
26
|
|
24
27
|
def build_object(data, context)
|
25
|
-
|
28
|
+
Node::MediaType.new(data, context)
|
26
29
|
end
|
27
30
|
|
28
31
|
def schema_factory(context)
|
@@ -32,12 +35,40 @@ module Openapi3Parser
|
|
32
35
|
|
33
36
|
def examples_factory(context)
|
34
37
|
factory = NodeFactory::OptionalReference.new(NodeFactories::Example)
|
35
|
-
NodeFactories::Map.new(context, value_factory: factory)
|
38
|
+
NodeFactories::Map.new(context, default: nil, value_factory: factory)
|
36
39
|
end
|
37
40
|
|
38
41
|
def encoding_factory(context)
|
39
|
-
|
40
|
-
|
42
|
+
NodeFactories::Map.new(
|
43
|
+
context,
|
44
|
+
validate: EncodingValidator.new(self),
|
45
|
+
value_factory: NodeFactories::Encoding
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
class EncodingValidator
|
50
|
+
def initialize(factory)
|
51
|
+
@factory = factory
|
52
|
+
end
|
53
|
+
|
54
|
+
def call(input, _context)
|
55
|
+
missing_keys = input.keys - properties
|
56
|
+
error_message(missing_keys) unless missing_keys.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
attr_reader :factory
|
62
|
+
|
63
|
+
def properties
|
64
|
+
properties = factory.resolved_input.dig("schema", "properties")
|
65
|
+
properties.respond_to?(:keys) ? properties.keys : []
|
66
|
+
end
|
67
|
+
|
68
|
+
def error_message(missing_keys)
|
69
|
+
keys = missing_keys.join(", ")
|
70
|
+
"Keys are not defined as schema properties: #{keys}"
|
71
|
+
end
|
41
72
|
end
|
42
73
|
end
|
43
74
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "openapi3_parser/
|
3
|
+
require "openapi3_parser/node/oauth_flow"
|
4
4
|
require "openapi3_parser/node_factory/object"
|
5
5
|
|
6
6
|
module Openapi3Parser
|
@@ -17,7 +17,7 @@ module Openapi3Parser
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def build_object(data, context)
|
20
|
-
|
20
|
+
Node::OauthFlow.new(data, context)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "openapi3_parser/
|
3
|
+
require "openapi3_parser/node/oauth_flows"
|
4
4
|
require "openapi3_parser/node_factories/oauth_flow"
|
5
5
|
require "openapi3_parser/node_factory/object"
|
6
6
|
require "openapi3_parser/node_factory/optional_reference"
|
@@ -24,7 +24,7 @@ module Openapi3Parser
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def build_object(data, context)
|
27
|
-
|
27
|
+
Node::OauthFlows.new(data, context)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "openapi3_parser/
|
3
|
+
require "openapi3_parser/node/openapi"
|
4
4
|
require "openapi3_parser/node_factory/object"
|
5
5
|
require "openapi3_parser/node_factories/info"
|
6
6
|
require "openapi3_parser/node_factories/array"
|
@@ -31,7 +31,7 @@ module Openapi3Parser
|
|
31
31
|
private
|
32
32
|
|
33
33
|
def build_object(data, context)
|
34
|
-
|
34
|
+
Node::Openapi.new(data, context)
|
35
35
|
end
|
36
36
|
|
37
37
|
def servers_factory(context)
|
@@ -45,7 +45,17 @@ module Openapi3Parser
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def tags_factory(context)
|
48
|
-
|
48
|
+
validate_unique_tags = lambda do |input, _context|
|
49
|
+
names = input.map { |i| i["name"] }
|
50
|
+
return if names.uniq.count == names.count
|
51
|
+
|
52
|
+
dupes = names.find_all { |name| names.count(name) > 1 }
|
53
|
+
"Duplicate tag names: #{dupes.uniq.join(', ')}"
|
54
|
+
end
|
55
|
+
|
56
|
+
NodeFactories::Array.new(context,
|
57
|
+
value_factory: NodeFactories::Tag,
|
58
|
+
validate: validate_unique_tags)
|
49
59
|
end
|
50
60
|
end
|
51
61
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "openapi3_parser/
|
3
|
+
require "openapi3_parser/node/operation"
|
4
4
|
require "openapi3_parser/node_factory/object"
|
5
5
|
require "openapi3_parser/node_factory/optional_reference"
|
6
6
|
require "openapi3_parser/node_factories/array"
|
@@ -11,6 +11,7 @@ require "openapi3_parser/node_factories/responses"
|
|
11
11
|
require "openapi3_parser/node_factories/callback"
|
12
12
|
require "openapi3_parser/node_factories/server"
|
13
13
|
require "openapi3_parser/node_factories/security_requirement"
|
14
|
+
require "openapi3_parser/validators/duplicate_parameters"
|
14
15
|
|
15
16
|
module Openapi3Parser
|
16
17
|
module NodeFactories
|
@@ -35,7 +36,7 @@ module Openapi3Parser
|
|
35
36
|
private
|
36
37
|
|
37
38
|
def build_object(data, context)
|
38
|
-
|
39
|
+
Node::Operation.new(data, context)
|
39
40
|
end
|
40
41
|
|
41
42
|
def tags_factory(context)
|
@@ -44,7 +45,14 @@ module Openapi3Parser
|
|
44
45
|
|
45
46
|
def parameters_factory(context)
|
46
47
|
factory = NodeFactory::OptionalReference.new(NodeFactories::Parameter)
|
47
|
-
|
48
|
+
|
49
|
+
validate = lambda do |_input, array_factory|
|
50
|
+
Validators::DuplicateParameters.call(array_factory.resolved_input)
|
51
|
+
end
|
52
|
+
|
53
|
+
NodeFactories::Array.new(context,
|
54
|
+
value_factory: factory,
|
55
|
+
validate: validate)
|
48
56
|
end
|
49
57
|
|
50
58
|
def request_body_factory(context)
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "openapi3_parser/
|
3
|
+
require "openapi3_parser/context"
|
4
|
+
require "openapi3_parser/node/parameter"
|
4
5
|
require "openapi3_parser/node_factories/parameter/parameter_like"
|
5
6
|
require "openapi3_parser/node_factory/object"
|
7
|
+
require "openapi3_parser/validation/error"
|
6
8
|
|
7
9
|
module Openapi3Parser
|
8
10
|
module NodeFactories
|
@@ -13,7 +15,9 @@ module Openapi3Parser
|
|
13
15
|
allow_extensions
|
14
16
|
|
15
17
|
field "name", input_type: String, required: true
|
16
|
-
field "in", input_type: String,
|
18
|
+
field "in", input_type: String,
|
19
|
+
required: true,
|
20
|
+
validate: :validate_in
|
17
21
|
field "description", input_type: String
|
18
22
|
field "required", input_type: :boolean, default: false
|
19
23
|
field "deprecated", input_type: :boolean, default: false
|
@@ -28,16 +32,37 @@ module Openapi3Parser
|
|
28
32
|
|
29
33
|
field "content", factory: :content_factory
|
30
34
|
|
35
|
+
mutually_exclusive "example", "examples"
|
36
|
+
|
31
37
|
private
|
32
38
|
|
33
39
|
def build_object(data, context)
|
34
|
-
|
40
|
+
Node::Parameter.new(data, context)
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate(input, context)
|
44
|
+
errors = []
|
45
|
+
|
46
|
+
if input["in"] == "path" && !input["required"]
|
47
|
+
errors << Validation::Error.new(
|
48
|
+
"Must be included and true for a path parameter",
|
49
|
+
Context.next_field(context, "required"),
|
50
|
+
self.class
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
errors
|
35
55
|
end
|
36
56
|
|
37
57
|
def default_style
|
38
58
|
return "simple" if %w[path header].include?(context.input["in"])
|
39
59
|
"form"
|
40
60
|
end
|
61
|
+
|
62
|
+
def validate_in(input)
|
63
|
+
valid = %w[header query cookie path].include?(input)
|
64
|
+
"in can only be header, query, cookie, or path" unless valid
|
65
|
+
end
|
41
66
|
end
|
42
67
|
end
|
43
68
|
end
|
@@ -15,14 +15,18 @@ module Openapi3Parser
|
|
15
15
|
|
16
16
|
def examples_factory(context)
|
17
17
|
factory = NodeFactory::OptionalReference.new(NodeFactories::Schema)
|
18
|
-
NodeFactories::Map.new(context, value_factory: factory)
|
18
|
+
NodeFactories::Map.new(context, default: nil, value_factory: factory)
|
19
19
|
end
|
20
20
|
|
21
21
|
def content_factory(context)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
NodeFactories::Map.new(context,
|
23
|
+
default: nil,
|
24
|
+
value_factory: NodeFactories::MediaType,
|
25
|
+
validate: method(:validate_content).to_proc)
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_content(input, _context)
|
29
|
+
"Must only have one item" unless input.size == 1
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "openapi3_parser/
|
3
|
+
require "openapi3_parser/node/path_item"
|
4
4
|
require "openapi3_parser/node_factory/fields/reference"
|
5
5
|
require "openapi3_parser/node_factory/object"
|
6
6
|
require "openapi3_parser/node_factory/object/node_builder"
|
@@ -9,6 +9,7 @@ require "openapi3_parser/node_factories/array"
|
|
9
9
|
require "openapi3_parser/node_factories/server"
|
10
10
|
require "openapi3_parser/node_factories/operation"
|
11
11
|
require "openapi3_parser/node_factories/parameter"
|
12
|
+
require "openapi3_parser/validators/duplicate_parameters"
|
12
13
|
|
13
14
|
module Openapi3Parser
|
14
15
|
module NodeFactories
|
@@ -38,12 +39,9 @@ module Openapi3Parser
|
|
38
39
|
|
39
40
|
def build_object(data, context)
|
40
41
|
ref = data.delete("$ref")
|
41
|
-
return
|
42
|
+
return Node::PathItem.new(data, context) unless ref
|
42
43
|
|
43
|
-
|
44
|
-
new.nil? ? old : new
|
45
|
-
end
|
46
|
-
Nodes::PathItem.new(merged_data, ref.node_context)
|
44
|
+
Node::PathItem.new(merge_data(ref.node_data, data), ref.node_context)
|
47
45
|
end
|
48
46
|
|
49
47
|
def ref_factory(context)
|
@@ -61,9 +59,30 @@ module Openapi3Parser
|
|
61
59
|
)
|
62
60
|
end
|
63
61
|
|
62
|
+
def build_resolved_input
|
63
|
+
ref = processed_input["$ref"]
|
64
|
+
data = super.tap { |d| d.delete("$ref") }
|
65
|
+
return data unless ref
|
66
|
+
|
67
|
+
merge_data(ref.data || {}, data)
|
68
|
+
end
|
69
|
+
|
70
|
+
def merge_data(base, priority)
|
71
|
+
base.merge(priority) do |_, new, old|
|
72
|
+
new.nil? ? old : new
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
64
76
|
def parameters_factory(context)
|
65
77
|
factory = NodeFactory::OptionalReference.new(NodeFactories::Parameter)
|
66
|
-
|
78
|
+
|
79
|
+
validate = lambda do |_input, array_factory|
|
80
|
+
Validators::DuplicateParameters.call(array_factory.resolved_input)
|
81
|
+
end
|
82
|
+
|
83
|
+
NodeFactories::Array.new(context,
|
84
|
+
value_factory: factory,
|
85
|
+
validate: validate)
|
67
86
|
end
|
68
87
|
end
|
69
88
|
end
|
@@ -3,12 +3,26 @@
|
|
3
3
|
require "openapi3_parser/node_factory/map"
|
4
4
|
require "openapi3_parser/node_factory/optional_reference"
|
5
5
|
require "openapi3_parser/node_factories/path_item"
|
6
|
-
require "openapi3_parser/
|
6
|
+
require "openapi3_parser/node/paths"
|
7
7
|
|
8
8
|
module Openapi3Parser
|
9
9
|
module NodeFactories
|
10
10
|
class Paths
|
11
11
|
include NodeFactory::Map
|
12
|
+
PATH_REGEX = %r{
|
13
|
+
\A
|
14
|
+
# required prefix slash
|
15
|
+
/
|
16
|
+
(
|
17
|
+
# Match a path
|
18
|
+
([\-;_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})*
|
19
|
+
# Match a path template parameter
|
20
|
+
({([\-;_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})+})*
|
21
|
+
# optional segment separating slash
|
22
|
+
/?
|
23
|
+
)*
|
24
|
+
\Z
|
25
|
+
}x
|
12
26
|
|
13
27
|
private
|
14
28
|
|
@@ -26,7 +40,42 @@ module Openapi3Parser
|
|
26
40
|
end
|
27
41
|
|
28
42
|
def build_map(data, context)
|
29
|
-
|
43
|
+
Node::Paths.new(data, context)
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate(input, _context)
|
47
|
+
paths = input.keys.reject { |key| extension?(key) }
|
48
|
+
validate_paths(paths)
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_paths(paths)
|
52
|
+
invalid_paths = paths.reject { |p| PATH_REGEX.match(p) }
|
53
|
+
errors = []
|
54
|
+
unless invalid_paths.empty?
|
55
|
+
joined = invalid_paths.map { |p| "'#{p}'" }.join(", ")
|
56
|
+
errors << %(There are invalid paths: #{joined})
|
57
|
+
end
|
58
|
+
|
59
|
+
conflicts = conflicting_paths(paths)
|
60
|
+
|
61
|
+
unless conflicts.empty?
|
62
|
+
joined = conflicts.map { |p| "'#{p}'" }.join(", ")
|
63
|
+
errors << %(There are paths that conflict: #{joined})
|
64
|
+
end
|
65
|
+
|
66
|
+
errors
|
67
|
+
end
|
68
|
+
|
69
|
+
def conflicting_paths(paths)
|
70
|
+
potential_conflicts = paths.each_with_object({}) do |path, memo|
|
71
|
+
without_params = path.gsub(/{.*?}/, "")
|
72
|
+
memo[path] = without_params if path != without_params
|
73
|
+
end
|
74
|
+
|
75
|
+
grouped_paths = potential_conflicts.group_by(&:last)
|
76
|
+
.map { |_k, v| v.map(&:first) }
|
77
|
+
|
78
|
+
grouped_paths.select { |group| group.size > 1 }.flatten
|
30
79
|
end
|
31
80
|
end
|
32
81
|
end
|