Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions lib/rage/openapi/parsers/ext/alba.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def __parse(klass_str)
visitor
end

class RequiredParam < String
end

class VisitorContext
attr_accessor :symbols, :hashes, :keywords, :consts, :nil

Expand Down Expand Up @@ -88,6 +91,7 @@ def build_schema

result["properties"] = @schema if @schema.any?

# TODO: root_key
if @root_key_proc
dynamic_root_key, dynamic_root_key_for_collection = @root_key_proc.call(@self_name)

Expand All @@ -109,6 +113,7 @@ def build_schema
result = { "type" => "object", "properties" => { @root_key => result, **@meta } }
end

result = deep_require_params(result)
result = deep_transform_keys(result) if @key_transformer

result
Expand All @@ -123,12 +128,14 @@ def visit_call_node(node)

when :attributes, :attribute
context = with_context { visit(node.arguments) }
context.symbols.each { |symbol| @segment[symbol] = { "type" => "string" } }
context.keywords.except("if").each { |key, type| @segment[key] = get_type_definition(type) }

key_class = !!context.keywords.delete("if") ? String : RequiredParam
context.symbols.each { |symbol| @segment[key_class.new(symbol)] = { "type" => "string" } }
context.keywords.each { |key, type| @segment[key_class.new(key)] = get_type_definition(type) }

when :nested, :nested_attribute
context = with_context { visit(node.arguments) }
with_inner_segment(context.symbols[0]) { visit(node.block) }
with_inner_segment(RequiredParam.new(context.symbols[0])) { visit(node.block) }

when :meta
context = with_context do
Expand All @@ -145,7 +152,9 @@ def visit_call_node(node)
is_array = node.name == :many || node.name == :has_many
context = with_context { visit(node.arguments) }
association = context.symbols[0]
key = context.keywords["key"] || association

key_class = context.keywords.has_key?("if") ? String : RequiredParam
key = key_class.new(context.keywords["key"] || association)

if node.block
with_inner_segment(key, is_array:) { visit(node.block) }
Expand Down Expand Up @@ -257,11 +266,32 @@ def hash_to_openapi_schema(hash)

def deep_transform_keys(schema)
schema.each_with_object({}) do |(key, value), memo|
if key == "required"
memo[key] = value.map { |v| @key_transformer.call(v) }
next
end

transformed_key = %w(type properties items additionalProperties).include?(key) ? key : @key_transformer.call(key)
memo[transformed_key] = value.is_a?(Hash) ? deep_transform_keys(value) : value
end
end

def deep_require_params(schema)
schema.keys.each do |key|
value = schema[key]

if value.is_a?(Hash)
deep_require_params(value)

if value["type"] == "object"
value["required"] = value["properties"].keys.select { |key| key.is_a?(RequiredParam) }
end
end
end

schema
end

def get_key_transformer(transformer_id)
return nil unless ::Alba.inflector

Expand Down
Loading