skooma 0.1.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 +7 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE.txt +21 -0
- data/README.md +125 -0
- data/data/oas-3.1/dialect/base.json +25 -0
- data/data/oas-3.1/meta/base.json +96 -0
- data/data/oas-3.1/schema/2022-10-07.json +1441 -0
- data/data/oas-3.1/schema-base/2022-10-07.json +23 -0
- data/lib/skooma/body_parsers.rb +31 -0
- data/lib/skooma/dialects/oas_3_1.rb +41 -0
- data/lib/skooma/inflector.rb +19 -0
- data/lib/skooma/instance.rb +112 -0
- data/lib/skooma/keywords/oas_3_1/dialect/discriminator.rb +13 -0
- data/lib/skooma/keywords/oas_3_1/dialect/example.rb +13 -0
- data/lib/skooma/keywords/oas_3_1/dialect/external_docs.rb +13 -0
- data/lib/skooma/keywords/oas_3_1/dialect/xml.rb +13 -0
- data/lib/skooma/keywords/oas_3_1/schema.rb +32 -0
- data/lib/skooma/keywords/oas_3_1.rb +22 -0
- data/lib/skooma/objects/base/keywords/deprecated.rb +13 -0
- data/lib/skooma/objects/base/keywords/description.rb +13 -0
- data/lib/skooma/objects/base/keywords/security.rb +13 -0
- data/lib/skooma/objects/base/keywords/servers.rb +13 -0
- data/lib/skooma/objects/base/keywords/summary.rb +13 -0
- data/lib/skooma/objects/base/keywords/tags.rb +13 -0
- data/lib/skooma/objects/base.rb +33 -0
- data/lib/skooma/objects/callback.rb +12 -0
- data/lib/skooma/objects/components.rb +30 -0
- data/lib/skooma/objects/header/keywords/content.rb +50 -0
- data/lib/skooma/objects/header/keywords/example.rb +13 -0
- data/lib/skooma/objects/header/keywords/examples.rb +13 -0
- data/lib/skooma/objects/header/keywords/explode.rb +13 -0
- data/lib/skooma/objects/header/keywords/required.rb +19 -0
- data/lib/skooma/objects/header/keywords/schema.rb +19 -0
- data/lib/skooma/objects/header/keywords/style.rb +13 -0
- data/lib/skooma/objects/header.rb +23 -0
- data/lib/skooma/objects/media_type.rb +14 -0
- data/lib/skooma/objects/openapi/keywords/components.rb +23 -0
- data/lib/skooma/objects/openapi/keywords/info.rb +13 -0
- data/lib/skooma/objects/openapi/keywords/json_schema_dialect.rb +21 -0
- data/lib/skooma/objects/openapi/keywords/openapi.rb +24 -0
- data/lib/skooma/objects/openapi/keywords/paths.rb +62 -0
- data/lib/skooma/objects/openapi/keywords/security.rb +13 -0
- data/lib/skooma/objects/openapi/keywords/webhooks.rb +15 -0
- data/lib/skooma/objects/openapi.rb +39 -0
- data/lib/skooma/objects/operation/keywords/callbacks.rb +13 -0
- data/lib/skooma/objects/operation/keywords/operation_id.rb +13 -0
- data/lib/skooma/objects/operation/keywords/parameters.rb +53 -0
- data/lib/skooma/objects/operation/keywords/request_body.rb +21 -0
- data/lib/skooma/objects/operation/keywords/responses.rb +48 -0
- data/lib/skooma/objects/operation.rb +31 -0
- data/lib/skooma/objects/parameter/keywords/allow_empty_value.rb +13 -0
- data/lib/skooma/objects/parameter/keywords/allow_reserved.rb +13 -0
- data/lib/skooma/objects/parameter/keywords/content.rb +21 -0
- data/lib/skooma/objects/parameter/keywords/in.rb +13 -0
- data/lib/skooma/objects/parameter/keywords/name.rb +13 -0
- data/lib/skooma/objects/parameter/keywords/required.rb +19 -0
- data/lib/skooma/objects/parameter/keywords/schema.rb +21 -0
- data/lib/skooma/objects/parameter/keywords/value_parser.rb +80 -0
- data/lib/skooma/objects/parameter.rb +27 -0
- data/lib/skooma/objects/path_item/keywords/base_operation.rb +25 -0
- data/lib/skooma/objects/path_item/keywords/delete.rb +16 -0
- data/lib/skooma/objects/path_item/keywords/get.rb +16 -0
- data/lib/skooma/objects/path_item/keywords/head.rb +16 -0
- data/lib/skooma/objects/path_item/keywords/options.rb +16 -0
- data/lib/skooma/objects/path_item/keywords/parameters.rb +19 -0
- data/lib/skooma/objects/path_item/keywords/patch.rb +16 -0
- data/lib/skooma/objects/path_item/keywords/post.rb +16 -0
- data/lib/skooma/objects/path_item/keywords/put.rb +16 -0
- data/lib/skooma/objects/path_item/keywords/trace.rb +16 -0
- data/lib/skooma/objects/path_item.rb +28 -0
- data/lib/skooma/objects/ref_base.rb +33 -0
- data/lib/skooma/objects/request_body/keywords/required.rb +19 -0
- data/lib/skooma/objects/request_body.rb +17 -0
- data/lib/skooma/objects/response/keywords/content.rb +51 -0
- data/lib/skooma/objects/response/keywords/headers.rb +37 -0
- data/lib/skooma/objects/response/keywords/links.rb +13 -0
- data/lib/skooma/objects/response.rb +18 -0
- data/lib/skooma/output_format.rb +35 -0
- data/lib/skooma/rspec.rb +166 -0
- data/lib/skooma/validators/double.rb +13 -0
- data/lib/skooma/validators/float.rb +13 -0
- data/lib/skooma/validators/int_32.rb +15 -0
- data/lib/skooma/validators/int_64.rb +15 -0
- data/lib/skooma/version.rb +5 -0
- data/lib/skooma.rb +26 -0
- metadata +161 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class OpenAPI
|
|
6
|
+
module Keywords
|
|
7
|
+
class Components < JSONSkooma::Keywords::Base
|
|
8
|
+
self.key = "components"
|
|
9
|
+
self.value_schema = :schema
|
|
10
|
+
self.schema_value_class = Objects::Components
|
|
11
|
+
|
|
12
|
+
def each_schema(&block)
|
|
13
|
+
return super unless json.type == "object"
|
|
14
|
+
|
|
15
|
+
json.each_value do |s|
|
|
16
|
+
s.each_value(&block)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class OpenAPI
|
|
6
|
+
module Keywords
|
|
7
|
+
class JSONSchemaDialect < JSONSkooma::Keywords::Base
|
|
8
|
+
self.key = "jsonSchemaDialect"
|
|
9
|
+
self.static = true
|
|
10
|
+
|
|
11
|
+
def initialize(parent_schema, value)
|
|
12
|
+
super
|
|
13
|
+
|
|
14
|
+
uri = URI.parse(value)
|
|
15
|
+
parent_schema.json_schema_dialect_uri = uri
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class OpenAPI
|
|
6
|
+
module Keywords
|
|
7
|
+
class OpenAPI < JSONSkooma::Keywords::BaseAnnotation
|
|
8
|
+
self.key = "openapi"
|
|
9
|
+
|
|
10
|
+
def initialize(parent_schema, value)
|
|
11
|
+
unless value.to_s.start_with? "3.1."
|
|
12
|
+
raise Error, "Only OpenAPI version 3.1.x is supported, got #{value}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
parent_schema.metaschema_uri = "https://spec.openapis.org/oas/3.1/schema-base/2022-10-07"
|
|
16
|
+
parent_schema.json_schema_dialect_uri = "https://spec.openapis.org/oas/3.1/dialect/base"
|
|
17
|
+
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class OpenAPI
|
|
6
|
+
module Keywords
|
|
7
|
+
class Paths < JSONSkooma::Keywords::Base
|
|
8
|
+
self.key = "paths"
|
|
9
|
+
self.value_schema = :object_of_schemas
|
|
10
|
+
self.schema_value_class = Objects::PathItem
|
|
11
|
+
|
|
12
|
+
ROUTE_REGEXP = /\{([^}]+)}/.freeze
|
|
13
|
+
|
|
14
|
+
def initialize(parent_schema, value)
|
|
15
|
+
super
|
|
16
|
+
@regexp_map = json.filter_map do |path, subschema|
|
|
17
|
+
next unless path.include?("{") && path.include?("}")
|
|
18
|
+
|
|
19
|
+
path_regex = path.gsub(ROUTE_REGEXP, "(?<\\1>[^/?#]+)")
|
|
20
|
+
path_regex = Regexp.new("\\A#{path_regex}\\z")
|
|
21
|
+
|
|
22
|
+
[path, path_regex, subschema]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def evaluate(instance, result)
|
|
27
|
+
path, attributes, path_schema = find_route(instance["path"])
|
|
28
|
+
|
|
29
|
+
return result.failure("Path #{instance["path"]} not found in schema") unless path
|
|
30
|
+
|
|
31
|
+
result.call(instance, path) do |subresult|
|
|
32
|
+
subresult.annotate({"path_attributes" => attributes})
|
|
33
|
+
path_schema.evaluate(instance, subresult)
|
|
34
|
+
|
|
35
|
+
if subresult.passed?
|
|
36
|
+
result.success
|
|
37
|
+
else
|
|
38
|
+
result.failure("Path #{instance["path"]} is invalid")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def find_route(instance_path)
|
|
46
|
+
return [instance_path, {}, json[instance_path]] if json.key?(instance_path)
|
|
47
|
+
|
|
48
|
+
@regexp_map.reduce(nil) do |result, (path, path_regex, subschema)|
|
|
49
|
+
next result unless path.include?("{") && path.include?("}")
|
|
50
|
+
|
|
51
|
+
match = instance_path.match(path_regex)
|
|
52
|
+
next result if match.nil?
|
|
53
|
+
next result if result && result[1].length <= match.named_captures.length
|
|
54
|
+
|
|
55
|
+
[path, match.named_captures, subschema]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class OpenAPI
|
|
6
|
+
module Keywords
|
|
7
|
+
# Map[string, Path Item Object | Reference Object] ]
|
|
8
|
+
# example: https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.1/webhook-example.yaml
|
|
9
|
+
class Webhooks < JSONSkooma::Keywords::BaseAnnotation
|
|
10
|
+
self.key = "webhooks"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
# OpenAPI Object – the root object of the OpenAPI document.
|
|
6
|
+
# https://spec.openapis.org/oas/v3.1.0#openapi-object
|
|
7
|
+
class OpenAPI < Base
|
|
8
|
+
attr_writer :json_schema_dialect_uri
|
|
9
|
+
|
|
10
|
+
def kw_classes
|
|
11
|
+
[
|
|
12
|
+
Keywords::Info,
|
|
13
|
+
Keywords::JSONSchemaDialect,
|
|
14
|
+
Keywords::Paths,
|
|
15
|
+
Keywords::Webhooks,
|
|
16
|
+
Keywords::Components,
|
|
17
|
+
Base::Keywords::Servers,
|
|
18
|
+
Base::Keywords::Security,
|
|
19
|
+
Base::Keywords::Tags,
|
|
20
|
+
Skooma::Keywords::OAS31::Dialect::ExternalDocs
|
|
21
|
+
]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def bootstrap(value)
|
|
25
|
+
# always evaluate openapi to check version,
|
|
26
|
+
# and set metaschema_uri and json_schema_dialect_uri
|
|
27
|
+
add_keyword(Keywords::OpenAPI.new(self, value["openapi"]))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def evaluate(instance, result = nil)
|
|
31
|
+
super(Instance.new(instance), result)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def json_schema_dialect_uri
|
|
35
|
+
@json_schema_dialect_uri || parent_schema&.json_schema_dialect_uri
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class Operation
|
|
6
|
+
module Keywords
|
|
7
|
+
class Parameters < JSONSkooma::Keywords::Base
|
|
8
|
+
self.key = "parameters"
|
|
9
|
+
self.value_schema = :array_of_schemas
|
|
10
|
+
self.schema_value_class = Objects::Parameter
|
|
11
|
+
|
|
12
|
+
def initialize(parent_schema, value)
|
|
13
|
+
super
|
|
14
|
+
keys = json.filter_map { |v| v["in"] && [v["in"].value, v["name"].value] }
|
|
15
|
+
parent_params = (parent_schema.parent["parameters"] || [])
|
|
16
|
+
parent_params.reject! do |v|
|
|
17
|
+
v["in"] && keys.include?([v["in"].value, v["name"].value])
|
|
18
|
+
end
|
|
19
|
+
@parent_params = parent_params
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def evaluate(instance, result)
|
|
23
|
+
return result.discard unless instance.key?("request")
|
|
24
|
+
return result.discard if json&.value&.empty? && @parent_params.empty?
|
|
25
|
+
|
|
26
|
+
errors = []
|
|
27
|
+
process_parameter(json, instance, result) do |subresult|
|
|
28
|
+
errors << [subresult.schema_node["in"], subresult.schema_node["name"]] unless subresult.passed?
|
|
29
|
+
end
|
|
30
|
+
process_parameter(@parent_params, instance, result.parent.sibling(instance, "parameters")) do |subresult|
|
|
31
|
+
key = [subresult.schema_node["in"], subresult.schema_node["name"]]
|
|
32
|
+
errors << key unless subresult.passed?
|
|
33
|
+
end
|
|
34
|
+
return if errors.empty?
|
|
35
|
+
|
|
36
|
+
result.failure("The following parameters are invalid: #{errors}")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def process_parameter(v, instance, result)
|
|
42
|
+
v.each.with_index do |param, index|
|
|
43
|
+
result.call(instance["request"], index.to_s) do |subresult|
|
|
44
|
+
param.evaluate(instance["request"], subresult)
|
|
45
|
+
yield subresult
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class Operation
|
|
6
|
+
module Keywords
|
|
7
|
+
class RequestBody < JSONSkooma::Keywords::Base
|
|
8
|
+
self.key = "requestBody"
|
|
9
|
+
self.value_schema = :schema
|
|
10
|
+
self.schema_value_class = Objects::RequestBody
|
|
11
|
+
|
|
12
|
+
def evaluate(instance, result)
|
|
13
|
+
return result.discard unless instance.key?("request")
|
|
14
|
+
|
|
15
|
+
json.evaluate(instance["request"], result)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class Operation
|
|
6
|
+
module Keywords
|
|
7
|
+
class Responses < JSONSkooma::Keywords::Base
|
|
8
|
+
self.key = "responses"
|
|
9
|
+
self.value_schema = :object_of_schemas
|
|
10
|
+
self.schema_value_class = Objects::Response
|
|
11
|
+
|
|
12
|
+
def evaluate(instance, result)
|
|
13
|
+
response = instance["response"] || {}
|
|
14
|
+
return result.discard unless response["status"]
|
|
15
|
+
|
|
16
|
+
status = find_status(response)
|
|
17
|
+
|
|
18
|
+
return result.failure("Status #{response["status"]} not found for #{instance["method"].upcase} #{instance["path"]}") unless status
|
|
19
|
+
|
|
20
|
+
result.annotate(status)
|
|
21
|
+
result.call(response["status"], status) do |status_result|
|
|
22
|
+
json[status].evaluate(response, status_result)
|
|
23
|
+
|
|
24
|
+
if status_result.passed?
|
|
25
|
+
result.annotate(status)
|
|
26
|
+
else
|
|
27
|
+
result.failure("Res #{response["status"]} is invalid")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def find_status(response)
|
|
35
|
+
response_status = response["status"].to_s
|
|
36
|
+
if json.key?(response_status)
|
|
37
|
+
response_status
|
|
38
|
+
elsif json.key?("#{response_status[0]}XX")
|
|
39
|
+
"#{response_status[0]}XX"
|
|
40
|
+
elsif json.key?("default")
|
|
41
|
+
"default"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
# Describes a single API operation on a path.
|
|
6
|
+
# https://spec.openapis.org/oas/v3.1.0#operation-object
|
|
7
|
+
class Operation < Base
|
|
8
|
+
def kw_classes
|
|
9
|
+
[
|
|
10
|
+
Base::Keywords::Tags,
|
|
11
|
+
Base::Keywords::Summary,
|
|
12
|
+
Base::Keywords::Description,
|
|
13
|
+
Skooma::Keywords::OAS31::Dialect::ExternalDocs,
|
|
14
|
+
Keywords::OperationId,
|
|
15
|
+
Keywords::Parameters,
|
|
16
|
+
Keywords::RequestBody,
|
|
17
|
+
Keywords::Responses,
|
|
18
|
+
Keywords::Callbacks,
|
|
19
|
+
Base::Keywords::Deprecated,
|
|
20
|
+
Base::Keywords::Security,
|
|
21
|
+
Base::Keywords::Servers
|
|
22
|
+
]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def bootstrap(value)
|
|
26
|
+
# always evaluate parameters to check parent parameters
|
|
27
|
+
add_keyword(Keywords::Parameters.new(self, value["parameters"] || []))
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class Parameter
|
|
6
|
+
module Keywords
|
|
7
|
+
class Content < Header::Keywords::Content
|
|
8
|
+
self.key = "content"
|
|
9
|
+
self.value_schema = :object_of_schemas
|
|
10
|
+
self.schema_value_class = Objects::MediaType
|
|
11
|
+
|
|
12
|
+
def evaluate(instance, result)
|
|
13
|
+
return if instance.value.nil?
|
|
14
|
+
|
|
15
|
+
super(ValueParser.call(instance, result), result)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class Parameter
|
|
6
|
+
module Keywords
|
|
7
|
+
class Required < JSONSkooma::Keywords::Base
|
|
8
|
+
self.key = "required"
|
|
9
|
+
|
|
10
|
+
def evaluate(instance, result)
|
|
11
|
+
if json.value && ValueParser.call(instance, result)&.value.nil?
|
|
12
|
+
result.failure("Parameter is required")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class Parameter
|
|
6
|
+
module Keywords
|
|
7
|
+
class Schema < Skooma::Keywords::OAS31::Schema
|
|
8
|
+
self.key = "schema"
|
|
9
|
+
self.depends_on = %w[in name style explode allowReserved allowEmptyValue]
|
|
10
|
+
|
|
11
|
+
def evaluate(instance, result)
|
|
12
|
+
value = ValueParser.call(instance, result)
|
|
13
|
+
return result.discard if value.nil?
|
|
14
|
+
|
|
15
|
+
super(value, result)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cgi"
|
|
4
|
+
|
|
5
|
+
module Skooma
|
|
6
|
+
module Objects
|
|
7
|
+
class Parameter
|
|
8
|
+
module Keywords
|
|
9
|
+
module ValueParser
|
|
10
|
+
class << self
|
|
11
|
+
def call(instance, result)
|
|
12
|
+
type = result.sibling(instance, "in").annotation
|
|
13
|
+
key = result.sibling(instance, "name").annotation
|
|
14
|
+
raise Error, "Missing key: #{key}" unless key
|
|
15
|
+
|
|
16
|
+
case type
|
|
17
|
+
when "query"
|
|
18
|
+
parse_query(instance)[key]
|
|
19
|
+
when "header"
|
|
20
|
+
instance["headers"][key]
|
|
21
|
+
when "path"
|
|
22
|
+
path_item_result = result.parent
|
|
23
|
+
path_item_result = path_item_result.parent until path_item_result.key.start_with?("/")
|
|
24
|
+
|
|
25
|
+
Instance::Attribute.new(
|
|
26
|
+
path_item_result.annotation["path_attributes"][key],
|
|
27
|
+
key: "path",
|
|
28
|
+
parent: instance["path"]
|
|
29
|
+
)
|
|
30
|
+
when "cookie"
|
|
31
|
+
# instance["headers"]["Cookie"]
|
|
32
|
+
else
|
|
33
|
+
raise Error, "Unknown location: #{result.sibling(instance, "in").annotation}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def parse_query(instance)
|
|
40
|
+
params = {}
|
|
41
|
+
instance["query"]&.value.to_s.split(/[&;]/).each do |pairs|
|
|
42
|
+
key, value = pairs.split("=", 2).collect { |v| CGI.unescape(v) }
|
|
43
|
+
next unless key
|
|
44
|
+
|
|
45
|
+
params[key] = value
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
Instance::Attribute.new(
|
|
49
|
+
params,
|
|
50
|
+
key: "query",
|
|
51
|
+
parent: instance["query"]
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def style(value, instance, result)
|
|
56
|
+
case result.sibling(instance, "style")
|
|
57
|
+
when "simple"
|
|
58
|
+
value
|
|
59
|
+
when "label"
|
|
60
|
+
value.split(".")
|
|
61
|
+
when "matrix"
|
|
62
|
+
value.split(";")
|
|
63
|
+
when "form"
|
|
64
|
+
value.split("&")
|
|
65
|
+
when "spaceDelimited"
|
|
66
|
+
value.split(" ")
|
|
67
|
+
when "pipeDelimited"
|
|
68
|
+
value.split("|")
|
|
69
|
+
when "deepObject"
|
|
70
|
+
raise Error, "Not implemented yet"
|
|
71
|
+
else
|
|
72
|
+
raise Error, "Unknown style: #{result.sibling(instance, "style")}"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
# https://spec.openapis.org/oas/v3.1.0#parameter-object
|
|
6
|
+
# Describes a single operation parameter.
|
|
7
|
+
class Parameter < RefBase
|
|
8
|
+
def kw_classes
|
|
9
|
+
[
|
|
10
|
+
Keywords::Name,
|
|
11
|
+
Keywords::In,
|
|
12
|
+
Base::Keywords::Description,
|
|
13
|
+
Base::Keywords::Deprecated,
|
|
14
|
+
Header::Keywords::Style,
|
|
15
|
+
Header::Keywords::Explode,
|
|
16
|
+
Keywords::AllowEmptyValue,
|
|
17
|
+
Keywords::AllowReserved,
|
|
18
|
+
Keywords::Required,
|
|
19
|
+
Keywords::Schema,
|
|
20
|
+
Header::Keywords::Example,
|
|
21
|
+
Header::Keywords::Examples,
|
|
22
|
+
Keywords::Content
|
|
23
|
+
]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skooma
|
|
4
|
+
module Objects
|
|
5
|
+
class PathItem
|
|
6
|
+
module Keywords
|
|
7
|
+
class BaseOperation < JSONSkooma::Keywords::Base
|
|
8
|
+
def evaluate(instance, result)
|
|
9
|
+
return result.discard unless instance["method"] == key
|
|
10
|
+
|
|
11
|
+
json.evaluate(instance, result)
|
|
12
|
+
return result.success if result.passed?
|
|
13
|
+
|
|
14
|
+
path_item_result = result.parent
|
|
15
|
+
path_item_result = path_item_result.parent until path_item_result.key.start_with?("/")
|
|
16
|
+
|
|
17
|
+
path = path_item_result.annotation["path"]
|
|
18
|
+
|
|
19
|
+
result.failure("Path #{path}/#{key} is invalid")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|