-module(oaspec@codegen@types). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/codegen/types.gleam"). -export([schema_to_gleam_type/2, schema_ref_to_type/2, collect_operations/1, schema_has_optional_fields/2, generate/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -file("src/oaspec/codegen/types.gleam", 481). ?DOC(" Get a status code suffix for anonymous type names.\n"). -spec status_code_suffix(binary()) -> binary(). status_code_suffix(Code) -> case Code of <<"200"/utf8>> -> <<"Ok"/utf8>>; <<"201"/utf8>> -> <<"Created"/utf8>>; <<"204"/utf8>> -> <<"NoContent"/utf8>>; <<"400"/utf8>> -> <<"BadRequest"/utf8>>; <<"401"/utf8>> -> <<"Unauthorized"/utf8>>; <<"403"/utf8>> -> <<"Forbidden"/utf8>>; <<"404"/utf8>> -> <<"NotFound"/utf8>>; <<"409"/utf8>> -> <<"Conflict"/utf8>>; <<"422"/utf8>> -> <<"UnprocessableEntity"/utf8>>; <<"500"/utf8>> -> <<"InternalServerError"/utf8>>; <<"default"/utf8>> -> <<"Default"/utf8>>; Other -> <<"Status"/utf8, Other/binary>> end. -file("src/oaspec/codegen/types.gleam", 589). ?DOC(" Convert a schema object to a Gleam type string.\n"). -spec schema_to_gleam_type( oaspec@openapi@schema:schema_object(), oaspec@codegen@context:context() ) -> binary(). schema_to_gleam_type(Schema, _) -> Base_type = case Schema of {string_schema, _, _, _, _, _, _, _} -> <<"String"/utf8>>; {integer_schema, _, _, _, _, _} -> <<"Int"/utf8>>; {number_schema, _, _, _, _, _} -> <<"Float"/utf8>>; {boolean_schema, _, _} -> <<"Bool"/utf8>>; {array_schema, _, Items, _, _, _} -> case Items of {reference, Ref} -> Name = oaspec@openapi@resolver:ref_to_name(Ref), <<<<"List("/utf8, (oaspec@util@naming:schema_to_type_name(Name))/binary>>/binary, ")"/utf8>>; {inline, Inner} -> Inner_type = case Inner of {string_schema, _, _, _, _, _, _, _} -> <<"String"/utf8>>; {integer_schema, _, _, _, _, _} -> <<"Int"/utf8>>; {number_schema, _, _, _, _, _} -> <<"Float"/utf8>>; {boolean_schema, _, _} -> <<"Bool"/utf8>>; _ -> <<"String"/utf8>> end, <<<<"List("/utf8, Inner_type/binary>>/binary, ")"/utf8>> end; {object_schema, _, _, _, _, _, _} -> <<"String"/utf8>>; {all_of_schema, _, _} -> <<"String"/utf8>>; {one_of_schema, _, _, _} -> <<"String"/utf8>>; {any_of_schema, _, _} -> <<"String"/utf8>> end, case oaspec@openapi@schema:is_nullable(Schema) of true -> <<<<"Option("/utf8, Base_type/binary>>/binary, ")"/utf8>>; false -> Base_type end. -file("src/oaspec/codegen/types.gleam", 517). ?DOC(" Convert a schema to a qualified Gleam type with types. prefix for compound types.\n"). -spec schema_to_gleam_type_qualified( oaspec@openapi@schema:schema_object(), binary(), binary(), oaspec@codegen@context:context() ) -> binary(). schema_to_gleam_type_qualified(Schema_obj, Op_id, Suffix, Ctx) -> case Schema_obj of {array_schema, _, Items, _, _, _} -> case Items of {reference, Ref} -> Name = oaspec@openapi@resolver:ref_to_name(Ref), <<<<"List(types."/utf8, (oaspec@util@naming:schema_to_type_name(Name))/binary>>/binary, ")"/utf8>>; _ -> schema_to_gleam_type(Schema_obj, Ctx) end; {object_schema, _, _, _, _, _, _} -> Type_name = <<(oaspec@util@naming:schema_to_type_name(Op_id))/binary, Suffix/binary>>, <<"types."/utf8, Type_name/binary>>; {one_of_schema, _, Schemas, _} -> All_refs = gleam@list:all(Schemas, fun(S) -> case S of {reference, _} -> true; _ -> false end end), case All_refs of true -> Type_name@1 = <<(oaspec@util@naming:schema_to_type_name( Op_id ))/binary, Suffix/binary>>, <<"types."/utf8, Type_name@1/binary>>; false -> schema_to_gleam_type(Schema_obj, Ctx) end; {any_of_schema, _, Schemas@1} -> All_refs@1 = gleam@list:all(Schemas@1, fun(S@1) -> case S@1 of {reference, _} -> true; _ -> false end end), case All_refs@1 of true -> Type_name@2 = <<(oaspec@util@naming:schema_to_type_name( Op_id ))/binary, Suffix/binary>>, <<"types."/utf8, Type_name@2/binary>>; false -> schema_to_gleam_type(Schema_obj, Ctx) end; {all_of_schema, _, _} -> Type_name@3 = <<(oaspec@util@naming:schema_to_type_name(Op_id))/binary, Suffix/binary>>, <<"types."/utf8, Type_name@3/binary>>; _ -> schema_to_gleam_type(Schema_obj, Ctx) end. -file("src/oaspec/codegen/types.gleam", 500). ?DOC( " Convert a SchemaRef to a qualified Gleam type string (with types. prefix).\n" " Used in response_types and request_types where types are in a separate module.\n" ). -spec schema_ref_to_type_qualified( oaspec@openapi@schema:schema_ref(), binary(), binary(), oaspec@codegen@context:context() ) -> binary(). schema_ref_to_type_qualified(Ref, Op_id, Suffix, Ctx) -> case Ref of {inline, Schema_obj} -> schema_to_gleam_type_qualified(Schema_obj, Op_id, Suffix, Ctx); {reference, Ref@1} -> Name = oaspec@openapi@resolver:ref_to_name(Ref@1), <<"types."/utf8, (oaspec@util@naming:schema_to_type_name(Name))/binary>> end. -file("src/oaspec/codegen/types.gleam", 578). ?DOC(" Convert a SchemaRef to a Gleam type string.\n"). -spec schema_ref_to_type( oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> binary(). schema_ref_to_type(Ref, Ctx) -> case Ref of {inline, Schema} -> schema_to_gleam_type(Schema, Ctx); {reference, Ref@1} -> Name = oaspec@openapi@resolver:ref_to_name(Ref@1), oaspec@util@naming:schema_to_type_name(Name) end. -file("src/oaspec/codegen/types.gleam", 288). ?DOC(" Convert a SchemaRef to a type string, using inline enum type if applicable.\n"). -spec schema_ref_to_type_with_inline_enum( oaspec@openapi@schema:schema_ref(), binary(), binary(), oaspec@codegen@context:context() ) -> binary(). schema_ref_to_type_with_inline_enum(Ref, Parent_name, Prop_name, Ctx) -> case Ref of {inline, {string_schema, _, _, Enum_values, _, _, _, _}} when Enum_values =/= [] -> <<(oaspec@util@naming:schema_to_type_name(Parent_name))/binary, (oaspec@util@naming:schema_to_type_name(Prop_name))/binary>>; _ -> schema_ref_to_type(Ref, Ctx) end. -file("src/oaspec/codegen/types.gleam", 808). ?DOC( " Convert an HTTP status code to a Gleam variant name.\n" " Prefixed with the type name to avoid duplicate constructors across types.\n" ). -spec status_code_to_variant(binary(), binary()) -> binary(). status_code_to_variant(Code, Type_name) -> Suffix = case Code of <<"200"/utf8>> -> <<"Ok"/utf8>>; <<"201"/utf8>> -> <<"Created"/utf8>>; <<"204"/utf8>> -> <<"NoContent"/utf8>>; <<"400"/utf8>> -> <<"BadRequest"/utf8>>; <<"401"/utf8>> -> <<"Unauthorized"/utf8>>; <<"403"/utf8>> -> <<"Forbidden"/utf8>>; <<"404"/utf8>> -> <<"NotFound"/utf8>>; <<"409"/utf8>> -> <<"Conflict"/utf8>>; <<"422"/utf8>> -> <<"UnprocessableEntity"/utf8>>; <<"500"/utf8>> -> <<"InternalServerError"/utf8>>; <<"default"/utf8>> -> <<"Default"/utf8>>; Other -> <<"Status"/utf8, Other/binary>> end, <>. -file("src/oaspec/codegen/types.gleam", 763). ?DOC(" Generate a response type for an operation.\n"). -spec generate_response_type( gleam@string_tree:string_tree(), binary(), oaspec@openapi@spec:operation(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_response_type(Sb, Op_id, Operation, Ctx) -> Type_name = <<(oaspec@util@naming:schema_to_type_name(Op_id))/binary, "Response"/utf8>>, Responses = maps:to_list(erlang:element(8, Operation)), case gleam@list:is_empty(Responses) of true -> Sb; false -> Sb@1 = begin _pipe = Sb, oaspec@util@string_extra:line( _pipe, <<<<"pub type "/utf8, Type_name/binary>>/binary, " {"/utf8>> ) end, Sb@3 = gleam@list:fold( Responses, Sb@1, fun(Sb@2, Entry) -> {Status_code, Response} = Entry, Variant_name = status_code_to_variant( Status_code, Type_name ), Content_entries = maps:to_list(erlang:element(3, Response)), case Content_entries of [] -> _pipe@1 = Sb@2, oaspec@util@string_extra:indent( _pipe@1, 1, Variant_name ); [{_, Media_type} | _] -> case erlang:element(2, Media_type) of {some, Ref} -> Suffix = <<"Response"/utf8, (status_code_suffix(Status_code))/binary>>, Inner_type = schema_ref_to_type_qualified( Ref, Op_id, Suffix, Ctx ), _pipe@2 = Sb@2, oaspec@util@string_extra:indent( _pipe@2, 1, <<<<<>/binary, Inner_type/binary>>/binary, ")"/utf8>> ); none -> _pipe@3 = Sb@2, oaspec@util@string_extra:indent( _pipe@3, 1, Variant_name ) end end end ), _pipe@4 = Sb@3, _pipe@5 = oaspec@util@string_extra:line(_pipe@4, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@5) end. -file("src/oaspec/codegen/types.gleam", 827). ?DOC(" Collect all operations from the spec with their IDs, paths, and methods.\n"). -spec collect_operations(oaspec@codegen@context:context()) -> list({binary(), oaspec@openapi@spec:operation(), binary(), oaspec@openapi@spec:http_method()}). collect_operations(Ctx) -> Paths = gleam@list:sort( maps:to_list(erlang:element(4, erlang:element(2, Ctx))), fun(A, B) -> gleam@string:compare(erlang:element(1, A), erlang:element(1, B)) end ), gleam@list:flat_map( Paths, fun(Entry) -> {Path, Path_item} = Entry, Ops = [{erlang:element(4, Path_item), get}, {erlang:element(5, Path_item), post}, {erlang:element(6, Path_item), put}, {erlang:element(7, Path_item), delete}, {erlang:element(8, Path_item), patch}], gleam@list:filter_map( Ops, fun(Op_entry) -> {Maybe_op, Method} = Op_entry, case Maybe_op of {some, Operation} -> Op_param_keys = gleam@list:map( erlang:element(6, Operation), fun(P) -> {erlang:element(2, P), erlang:element(3, P)} end ), Inherited_params = gleam@list:filter( erlang:element(9, Path_item), fun(P@1) -> not gleam@list:contains( Op_param_keys, {erlang:element(2, P@1), erlang:element(3, P@1)} ) end ), Merged_params = lists:append( Inherited_params, erlang:element(6, Operation) ), Effective_security = case erlang:element( 10, Operation ) of {some, Sec} -> Sec; none -> erlang:element(7, erlang:element(2, Ctx)) end, Operation@1 = {operation, erlang:element(2, Operation), erlang:element(3, Operation), erlang:element(4, Operation), erlang:element(5, Operation), Merged_params, erlang:element(7, Operation), erlang:element(8, Operation), erlang:element(9, Operation), {some, Effective_security}}, Op_id = case erlang:element(2, Operation@1) of {some, Id} -> Id; none -> <<<<(oaspec@openapi@spec:method_to_lower( Method ))/binary, "_"/utf8>>/binary, (begin _pipe = gleam@string:replace( Path, <<"/"/utf8>>, <<"_"/utf8>> ), _pipe@1 = gleam@string:replace( _pipe, <<"{"/utf8>>, <<""/utf8>> ), gleam@string:replace( _pipe@1, <<"}"/utf8>>, <<""/utf8>> ) end)/binary>> end, {ok, {Op_id, Operation@1, Path, Method}}; none -> {error, nil} end end ) end ). -file("src/oaspec/codegen/types.gleam", 746). ?DOC(" Generate response types for all operations.\n"). -spec generate_response_types(oaspec@codegen@context:context()) -> binary(). generate_response_types(Ctx) -> Sb = begin _pipe = oaspec@util@string_extra:file_header(<<"0.3.0"/utf8>>), oaspec@util@string_extra:imports( _pipe, [<<(erlang:element(5, erlang:element(3, Ctx)))/binary, "/types"/utf8>>] ) end, Operations = collect_operations(Ctx), Sb@2 = gleam@list:fold( Operations, Sb, fun(Sb@1, Op) -> {Op_id, Operation, _, _} = Op, generate_response_type(Sb@1, Op_id, Operation, Ctx) end ), oaspec@util@string_extra:to_string(Sb@2). -file("src/oaspec/codegen/types.gleam", 913). ?DOC(" Check if a SchemaRef is nullable, resolving $ref if needed.\n"). -spec schema_ref_is_nullable( oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> boolean(). schema_ref_is_nullable(Ref, Ctx) -> case Ref of {inline, S} -> oaspec@openapi@schema:is_nullable(S); {reference, _} -> case oaspec@openapi@resolver:resolve_schema_ref( Ref, erlang:element(2, Ctx) ) of {ok, S@1} -> oaspec@openapi@schema:is_nullable(S@1); {error, _} -> false end end. -file("src/oaspec/codegen/types.gleam", 889). ?DOC(" Check if a schema has any optional or nullable fields that would need Option.\n"). -spec schema_has_optional_fields( oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> boolean(). schema_has_optional_fields(Schema_ref, Ctx) -> case Schema_ref of {inline, {object_schema, _, Properties, Required, _, _, _}} -> Has_optional = begin _pipe = maps:to_list(Properties), gleam@list:any( _pipe, fun(Entry) -> {Prop_name, Prop_ref} = Entry, not gleam@list:contains(Required, Prop_name) orelse schema_ref_is_nullable( Prop_ref, Ctx ) end ) end, Has_optional; {inline, {all_of_schema, _, Schemas}} -> gleam@list:any( Schemas, fun(S) -> schema_has_optional_fields(S, Ctx) end ); {reference, _} -> case oaspec@openapi@resolver:resolve_schema_ref( Schema_ref, erlang:element(2, Ctx) ) of {ok, Schema_obj} -> schema_has_optional_fields({inline, Schema_obj}, Ctx); {error, _} -> false end; _ -> false end. -file("src/oaspec/codegen/types.gleam", 946). ?DOC(" Extract the type for an inline request body schema.\n"). -spec extract_inline_request_body_type( oaspec@openapi@schema:schema_object(), binary(), oaspec@codegen@context:context() ) -> binary(). extract_inline_request_body_type(Schema_obj, Op_id, Ctx) -> case Schema_obj of {object_schema, _, _, _, _, _, _} -> Type_name = <<(oaspec@util@naming:schema_to_type_name(Op_id))/binary, "RequestBody"/utf8>>, <<"types."/utf8, Type_name/binary>>; {all_of_schema, _, _} -> Type_name@1 = <<(oaspec@util@naming:schema_to_type_name(Op_id))/binary, "RequestBody"/utf8>>, <<"types."/utf8, Type_name@1/binary>>; {string_schema, _, _, _, _, _, _, _} -> <<"String"/utf8>>; {integer_schema, _, _, _, _, _} -> <<"Int"/utf8>>; {number_schema, _, _, _, _, _} -> <<"Float"/utf8>>; {boolean_schema, _, _} -> <<"Bool"/utf8>>; _ -> schema_to_gleam_type(Schema_obj, Ctx) end. -file("src/oaspec/codegen/types.gleam", 926). ?DOC( " Extract the Gleam type for a request body from its content media types.\n" " Uses types. prefix since request body schemas live in the types module.\n" ). -spec extract_request_body_type( oaspec@openapi@spec:request_body(), binary(), oaspec@codegen@context:context() ) -> binary(). extract_request_body_type(Rb, Op_id, Ctx) -> Content_entries = maps:to_list(erlang:element(3, Rb)), case Content_entries of [{_, Media_type} | _] -> case erlang:element(2, Media_type) of {some, {reference, Ref}} -> <<"types."/utf8, (oaspec@util@naming:schema_to_type_name( oaspec@openapi@resolver:ref_to_name(Ref) ))/binary>>; {some, {inline, Schema_obj}} -> extract_inline_request_body_type(Schema_obj, Op_id, Ctx); _ -> <<"String"/utf8>> end; [] -> <<"String"/utf8>> end. -file("src/oaspec/codegen/types.gleam", 685). ?DOC(" Generate a single request type for an operation.\n"). -spec generate_request_type( gleam@string_tree:string_tree(), binary(), oaspec@openapi@spec:operation(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_request_type(Sb, Op_id, Operation, Ctx) -> Type_name = <<(oaspec@util@naming:schema_to_type_name(Op_id))/binary, "Request"/utf8>>, Params = erlang:element(6, Operation), case gleam@list:is_empty(Params) andalso gleam@option:is_none( erlang:element(7, Operation) ) of true -> Sb; false -> Sb@1 = case erlang:element(4, Operation) of {some, Desc} -> _pipe = Sb, oaspec@util@string_extra:doc_comment(_pipe, Desc); none -> Sb end, Sb@2 = begin _pipe@1 = Sb@1, oaspec@util@string_extra:line( _pipe@1, <<<<"pub type "/utf8, Type_name/binary>>/binary, " {"/utf8>> ) end, Sb@3 = begin _pipe@2 = Sb@2, oaspec@util@string_extra:indent( _pipe@2, 1, <> ) end, Sb@5 = gleam@list:index_fold( Params, Sb@3, fun(Sb@4, Param, Idx) -> Field_name = oaspec@util@naming:to_snake_case( erlang:element(2, Param) ), Field_type = case erlang:element(6, Param) of {some, {inline, {string_schema, _, _, _, _, _, _, _}}} -> <<"String"/utf8>>; {some, {inline, {integer_schema, _, _, _, _, _}}} -> <<"Int"/utf8>>; {some, {inline, {number_schema, _, _, _, _, _}}} -> <<"Float"/utf8>>; {some, {inline, {boolean_schema, _, _}}} -> <<"Bool"/utf8>>; {some, {reference, Ref}} -> oaspec@util@naming:schema_to_type_name( oaspec@openapi@resolver:ref_to_name(Ref) ); _ -> <<"String"/utf8>> end, Final_type = case erlang:element(5, Param) of true -> Field_type; false -> <<<<"Option("/utf8, Field_type/binary>>/binary, ")"/utf8>> end, Has_more = Idx < (erlang:length(Params) - 1), Has_body = gleam@option:is_some( erlang:element(7, Operation) ), Trailing = case Has_more orelse Has_body of true -> <<","/utf8>>; false -> <<""/utf8>> end, _pipe@3 = Sb@4, oaspec@util@string_extra:indent( _pipe@3, 2, <<<<<>/binary, Final_type/binary>>/binary, Trailing/binary>> ) end ), Sb@6 = case erlang:element(7, Operation) of {some, Rb} -> Body_type = extract_request_body_type(Rb, Op_id, Ctx), _pipe@4 = Sb@5, oaspec@util@string_extra:indent( _pipe@4, 2, <<"body: "/utf8, Body_type/binary>> ); none -> Sb@5 end, _pipe@5 = Sb@6, _pipe@6 = oaspec@util@string_extra:indent(_pipe@5, 1, <<")"/utf8>>), _pipe@7 = oaspec@util@string_extra:line(_pipe@6, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@7) end. -file("src/oaspec/codegen/types.gleam", 625). ?DOC(" Generate request types for all operations.\n"). -spec generate_request_types(oaspec@codegen@context:context()) -> binary(). generate_request_types(Ctx) -> Operations = collect_operations(Ctx), Needs_option = gleam@list:any( Operations, fun(Op) -> {_, Operation, _, _} = Op, gleam@list:any( erlang:element(6, Operation), fun(P) -> not erlang:element(5, P) end ) end ), Needs_types = gleam@list:any( Operations, fun(Op@1) -> {_, Operation@1, _, _} = Op@1, Has_ref_params = gleam@list:any( erlang:element(6, Operation@1), fun(P@1) -> case erlang:element(6, P@1) of {some, {reference, _}} -> true; _ -> false end end ), Has_typed_body = case erlang:element(7, Operation@1) of {some, Rb} -> gleam@list:any( maps:to_list(erlang:element(3, Rb)), fun(Ce) -> {_, Mt} = Ce, case erlang:element(2, Mt) of {some, {reference, _}} -> true; {some, {inline, {object_schema, _, _, _, _, _, _}}} -> true; {some, {inline, {all_of_schema, _, _}}} -> true; _ -> false end end ); _ -> false end, Has_ref_params orelse Has_typed_body end ), Base_imports = case Needs_types of true -> [<<(erlang:element(5, erlang:element(3, Ctx)))/binary, "/types"/utf8>>]; false -> [] end, Imports = case Needs_option of true -> [<<"gleam/option.{type Option}"/utf8>> | Base_imports]; false -> Base_imports end, Sb = begin _pipe = oaspec@util@string_extra:file_header(<<"0.3.0"/utf8>>), oaspec@util@string_extra:imports(_pipe, Imports) end, Sb@2 = gleam@list:fold( Operations, Sb, fun(Sb@1, Op@2) -> {Op_id, Operation@2, _, _} = Op@2, generate_request_type(Sb@1, Op_id, Operation@2, Ctx) end ), oaspec@util@string_extra:to_string(Sb@2). -file("src/oaspec/codegen/types.gleam", 969). ?DOC(" Add a doc comment if description is present.\n"). -spec maybe_doc_comment( gleam@string_tree:string_tree(), gleam@option:option(binary()) ) -> gleam@string_tree:string_tree(). maybe_doc_comment(Sb, Description) -> case Description of {some, Desc} -> _pipe = Sb, oaspec@util@string_extra:doc_comment(_pipe, Desc); none -> Sb end. -file("src/oaspec/codegen/types.gleam", 108). ?DOC(" Generate enum types for any properties that have inline enum values.\n"). -spec generate_inline_enums_from_properties( gleam@string_tree:string_tree(), binary(), gleam@dict:dict(binary(), oaspec@openapi@schema:schema_ref()), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_inline_enums_from_properties(Sb, Parent_name, Properties, _) -> Entries = maps:to_list(Properties), gleam@list:fold( Entries, Sb, fun(Sb@1, Entry) -> {Prop_name, Prop_ref} = Entry, case Prop_ref of {inline, {string_schema, Description, _, Enum_values, _, _, _, _}} when Enum_values =/= [] -> Type_name = <<(oaspec@util@naming:schema_to_type_name( Parent_name ))/binary, (oaspec@util@naming:schema_to_type_name(Prop_name))/binary>>, Sb@2 = maybe_doc_comment(Sb@1, Description), Sb@3 = begin _pipe = Sb@2, oaspec@util@string_extra:line( _pipe, <<<<"pub type "/utf8, Type_name/binary>>/binary, " {"/utf8>> ) end, Sb@5 = gleam@list:fold( Enum_values, Sb@3, fun(Sb@4, Value) -> Variant_name = oaspec@util@naming:schema_to_type_name( <<<>/binary, Value/binary>> ), _pipe@1 = Sb@4, oaspec@util@string_extra:indent( _pipe@1, 1, Variant_name ) end ), _pipe@2 = Sb@5, _pipe@3 = oaspec@util@string_extra:line( _pipe@2, <<"}"/utf8>> ), oaspec@util@string_extra:blank_line(_pipe@3); _ -> Sb@1 end end ). -file("src/oaspec/codegen/types.gleam", 78). ?DOC( " Generate inline enum types found in object schema properties.\n" " These are generated as separate types before the parent type.\n" ). -spec generate_inline_enums_for_schema( gleam@string_tree:string_tree(), binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_inline_enums_for_schema(Sb, Parent_name, Schema_ref, Ctx) -> case Schema_ref of {inline, {object_schema, _, Properties, _, _, _, _}} -> generate_inline_enums_from_properties( Sb, Parent_name, Properties, Ctx ); {inline, {all_of_schema, _, Schemas}} -> Merged_props = gleam@list:fold( Schemas, maps:new(), fun(Acc, S_ref) -> case S_ref of {inline, {object_schema, _, Properties@1, _, _, _, _}} -> maps:merge(Acc, Properties@1); {reference, _} -> case oaspec@openapi@resolver:resolve_schema_ref( S_ref, erlang:element(2, Ctx) ) of {ok, {object_schema, _, Properties@2, _, _, _, _}} -> maps:merge(Acc, Properties@2); _ -> Acc end; _ -> Acc end end ), generate_inline_enums_from_properties( Sb, Parent_name, Merged_props, Ctx ); _ -> Sb end. -file("src/oaspec/codegen/types.gleam", 161). ?DOC(" Generate a type from a schema object.\n"). -spec generate_schema_type( gleam@string_tree:string_tree(), binary(), binary(), oaspec@openapi@schema:schema_object(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_schema_type(Sb, Type_name, Raw_name, Schema, Ctx) -> case Schema of {object_schema, Description, Properties, Required, _, _, _} -> Sb@1 = maybe_doc_comment(Sb, Description), Sb@2 = begin _pipe = Sb@1, oaspec@util@string_extra:line( _pipe, <<<<"pub type "/utf8, Type_name/binary>>/binary, " {"/utf8>> ) end, Sb@3 = begin _pipe@1 = Sb@2, oaspec@util@string_extra:indent( _pipe@1, 1, <> ) end, Props = maps:to_list(Properties), Sb@5 = gleam@list:index_fold( Props, Sb@3, fun(Sb@4, Entry, Idx) -> {Prop_name, Prop_ref} = Entry, Field_name = oaspec@util@naming:to_snake_case(Prop_name), Field_type = schema_ref_to_type_with_inline_enum( Prop_ref, Raw_name, Prop_name, Ctx ), Is_required = gleam@list:contains(Required, Prop_name), Is_already_optional = schema_ref_is_nullable(Prop_ref, Ctx), Final_type = case {Is_required, Is_already_optional} of {true, _} -> Field_type; {false, true} -> Field_type; {false, false} -> <<<<"Option("/utf8, Field_type/binary>>/binary, ")"/utf8>> end, Trailing = case Idx =:= (erlang:length(Props) - 1) of true -> <<""/utf8>>; false -> <<","/utf8>> end, _pipe@2 = Sb@4, oaspec@util@string_extra:indent( _pipe@2, 2, <<<<<>/binary, Final_type/binary>>/binary, Trailing/binary>> ) end ), _pipe@3 = Sb@5, _pipe@4 = oaspec@util@string_extra:indent(_pipe@3, 1, <<")"/utf8>>), _pipe@5 = oaspec@util@string_extra:line(_pipe@4, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@5); {string_schema, Description@1, _, Enum_values, _, _, _, _} when Enum_values =/= [] -> Sb@6 = maybe_doc_comment(Sb, Description@1), Sb@7 = begin _pipe@6 = Sb@6, oaspec@util@string_extra:line( _pipe@6, <<<<"pub type "/utf8, Type_name/binary>>/binary, " {"/utf8>> ) end, Sb@9 = gleam@list:fold( Enum_values, Sb@7, fun(Sb@8, Value) -> Variant_name = oaspec@util@naming:schema_to_type_name( <<<>/binary, Value/binary>> ), _pipe@7 = Sb@8, oaspec@util@string_extra:indent(_pipe@7, 1, Variant_name) end ), _pipe@8 = Sb@9, _pipe@9 = oaspec@util@string_extra:line(_pipe@8, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@9); {one_of_schema, Description@2, Schemas, _} -> Sb@10 = maybe_doc_comment(Sb, Description@2), Sb@11 = begin _pipe@10 = Sb@10, oaspec@util@string_extra:line( _pipe@10, <<<<"pub type "/utf8, Type_name/binary>>/binary, " {"/utf8>> ) end, Sb@13 = gleam@list:fold( Schemas, Sb@11, fun(Sb@12, S_ref) -> Variant_type = schema_ref_to_type(S_ref, Ctx), Variant_name@1 = <>, _pipe@11 = Sb@12, oaspec@util@string_extra:indent( _pipe@11, 1, <<<<<>/binary, Variant_type/binary>>/binary, ")"/utf8>> ) end ), _pipe@12 = Sb@13, _pipe@13 = oaspec@util@string_extra:line(_pipe@12, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@13); {all_of_schema, Description@3, Schemas@1} -> Sb@14 = maybe_doc_comment(Sb, Description@3), Merged_props = gleam@list:fold( Schemas@1, maps:new(), fun(Acc, S_ref@1) -> case S_ref@1 of {inline, {object_schema, _, Properties@1, _, _, _, _}} -> maps:merge(Acc, Properties@1); {reference, _} -> case oaspec@openapi@resolver:resolve_schema_ref( S_ref@1, erlang:element(2, Ctx) ) of {ok, {object_schema, _, Properties@2, _, _, _, _}} -> maps:merge(Acc, Properties@2); _ -> Acc end; _ -> Acc end end ), Merged_required = gleam@list:flat_map( Schemas@1, fun(S_ref@2) -> case S_ref@2 of {inline, {object_schema, _, _, Required@1, _, _, _}} -> Required@1; {reference, _} -> case oaspec@openapi@resolver:resolve_schema_ref( S_ref@2, erlang:element(2, Ctx) ) of {ok, {object_schema, _, _, Required@2, _, _, _}} -> Required@2; _ -> [] end; _ -> [] end end ), Merged_schema = {object_schema, Description@3, Merged_props, Merged_required, none, false, false}, generate_schema_type(Sb@14, Type_name, Raw_name, Merged_schema, Ctx); _ -> Gleam_type = schema_to_gleam_type(Schema, Ctx), _pipe@14 = Sb, _pipe@15 = oaspec@util@string_extra:line( _pipe@14, <<<<<<"pub type "/utf8, Type_name/binary>>/binary, " = "/utf8>>/binary, Gleam_type/binary>> ), oaspec@util@string_extra:blank_line(_pipe@15) end. -file("src/oaspec/codegen/types.gleam", 140). ?DOC(" Generate a single type definition.\n"). -spec generate_type_def( gleam@string_tree:string_tree(), binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_type_def(Sb, Name, Schema_ref, Ctx) -> Type_name = oaspec@util@naming:schema_to_type_name(Name), case Schema_ref of {inline, Schema} -> generate_schema_type(Sb, Type_name, Name, Schema, Ctx); {reference, Ref} -> Resolved_name = oaspec@openapi@resolver:ref_to_name(Ref), Resolved_type = oaspec@util@naming:schema_to_type_name( Resolved_name ), _pipe = Sb, _pipe@1 = oaspec@util@string_extra:line( _pipe, <<<<<<"pub type "/utf8, Type_name/binary>>/binary, " = "/utf8>>/binary, Resolved_type/binary>> ), oaspec@util@string_extra:blank_line(_pipe@1) end. -file("src/oaspec/codegen/types.gleam", 377). ?DOC(" Generate a named type for an inline schema object.\n"). -spec generate_anonymous_type_for_schema( gleam@string_tree:string_tree(), binary(), binary(), oaspec@openapi@schema:schema_object(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_anonymous_type_for_schema(Sb, Op_id, Suffix, Schema_obj, Ctx) -> Type_name = <<(oaspec@util@naming:schema_to_type_name(Op_id))/binary, Suffix/binary>>, Raw_name = <<<>/binary, Suffix/binary>>, case Schema_obj of {object_schema, _, _, _, _, _, _} -> generate_schema_type(Sb, Type_name, Raw_name, Schema_obj, Ctx); {one_of_schema, _, Schemas, _} -> All_refs = gleam@list:all(Schemas, fun(S) -> case S of {reference, _} -> true; _ -> false end end), case All_refs of true -> Sb@1 = begin _pipe = Sb, oaspec@util@string_extra:line( _pipe, <<<<"pub type "/utf8, Type_name/binary>>/binary, " {"/utf8>> ) end, Sb@3 = gleam@list:fold( Schemas, Sb@1, fun(Sb@2, S_ref) -> Variant_type = schema_ref_to_type(S_ref, Ctx), Variant_name = <>, _pipe@1 = Sb@2, oaspec@util@string_extra:indent( _pipe@1, 1, <<<<<>/binary, Variant_type/binary>>/binary, ")"/utf8>> ) end ), _pipe@2 = Sb@3, _pipe@3 = oaspec@util@string_extra:line( _pipe@2, <<"}"/utf8>> ), oaspec@util@string_extra:blank_line(_pipe@3); false -> Sb end; {any_of_schema, _, Schemas@1} -> All_refs@1 = gleam@list:all(Schemas@1, fun(S@1) -> case S@1 of {reference, _} -> true; _ -> false end end), case All_refs@1 of true -> Sb@4 = begin _pipe@4 = Sb, oaspec@util@string_extra:line( _pipe@4, <<<<"pub type "/utf8, Type_name/binary>>/binary, " {"/utf8>> ) end, Sb@6 = gleam@list:fold( Schemas@1, Sb@4, fun(Sb@5, S_ref@1) -> Variant_type@1 = schema_ref_to_type(S_ref@1, Ctx), Variant_name@1 = <>, _pipe@5 = Sb@5, oaspec@util@string_extra:indent( _pipe@5, 1, <<<<<>/binary, Variant_type@1/binary>>/binary, ")"/utf8>> ) end ), _pipe@6 = Sb@6, _pipe@7 = oaspec@util@string_extra:line( _pipe@6, <<"}"/utf8>> ), oaspec@util@string_extra:blank_line(_pipe@7); false -> Sb end; {all_of_schema, Description, Schemas@2} -> Merged_props = gleam@list:fold( Schemas@2, maps:new(), fun(Acc, S_ref@2) -> case S_ref@2 of {inline, {object_schema, _, Properties, _, _, _, _}} -> maps:merge(Acc, Properties); {reference, _} -> case oaspec@openapi@resolver:resolve_schema_ref( S_ref@2, erlang:element(2, Ctx) ) of {ok, {object_schema, _, Properties@1, _, _, _, _}} -> maps:merge(Acc, Properties@1); _ -> Acc end; _ -> Acc end end ), Merged_required = gleam@list:flat_map( Schemas@2, fun(S_ref@3) -> case S_ref@3 of {inline, {object_schema, _, _, Required, _, _, _}} -> Required; {reference, _} -> case oaspec@openapi@resolver:resolve_schema_ref( S_ref@3, erlang:element(2, Ctx) ) of {ok, {object_schema, _, _, Required@1, _, _, _}} -> Required@1; _ -> [] end; _ -> [] end end ), Merged_schema = {object_schema, Description, Merged_props, Merged_required, none, false, false}, generate_schema_type(Sb, Type_name, Raw_name, Merged_schema, Ctx); _ -> Sb end. -file("src/oaspec/codegen/types.gleam", 318). ?DOC(" Generate anonymous types for inline response schemas.\n"). -spec generate_anonymous_response_types( gleam@string_tree:string_tree(), binary(), oaspec@openapi@spec:operation(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_anonymous_response_types(Sb, Op_id, Operation, Ctx) -> Responses = maps:to_list(erlang:element(8, Operation)), gleam@list:fold( Responses, Sb, fun(Sb@1, Entry) -> {Status_code, Response} = Entry, Content_entries = maps:to_list(erlang:element(3, Response)), case Content_entries of [{_, Media_type} | _] -> case erlang:element(2, Media_type) of {some, {inline, Schema_obj}} -> generate_anonymous_type_for_schema( Sb@1, Op_id, <<"Response"/utf8, (status_code_suffix(Status_code))/binary>>, Schema_obj, Ctx ); _ -> Sb@1 end; _ -> Sb@1 end end ). -file("src/oaspec/codegen/types.gleam", 347). ?DOC(" Generate anonymous type for a request body if it has an inline schema.\n"). -spec generate_anonymous_request_body_type( gleam@string_tree:string_tree(), binary(), oaspec@openapi@spec:operation(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_anonymous_request_body_type(Sb, Op_id, Operation, Ctx) -> case erlang:element(7, Operation) of {some, Rb} -> Content_entries = maps:to_list(erlang:element(3, Rb)), case Content_entries of [{_, Media_type} | _] -> case erlang:element(2, Media_type) of {some, {inline, Schema_obj}} -> generate_anonymous_type_for_schema( Sb, Op_id, <<"RequestBody"/utf8>>, Schema_obj, Ctx ); _ -> Sb end; _ -> Sb end; none -> Sb end. -file("src/oaspec/codegen/types.gleam", 304). ?DOC(" Generate anonymous types from inline schemas in operations.\n"). -spec generate_anonymous_types( gleam@string_tree:string_tree(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_anonymous_types(Sb, Ctx) -> Operations = collect_operations(Ctx), gleam@list:fold( Operations, Sb, fun(Sb@1, Op) -> {Op_id, Operation, _, _} = Op, Sb@2 = generate_anonymous_response_types( Sb@1, Op_id, Operation, Ctx ), Sb@3 = generate_anonymous_request_body_type( Sb@2, Op_id, Operation, Ctx ), Sb@3 end ). -file("src/oaspec/codegen/types.gleam", 30). ?DOC(" Generate types from component schemas and anonymous types from operations.\n"). -spec generate_types(oaspec@codegen@context:context()) -> binary(). generate_types(Ctx) -> Schemas = case erlang:element(5, erlang:element(2, Ctx)) of {some, Components} -> gleam@list:sort( maps:to_list(erlang:element(2, Components)), fun(A, B) -> gleam@string:compare( erlang:element(1, A), erlang:element(1, B) ) end ); none -> [] end, Needs_option = gleam@list:any( Schemas, fun(Entry) -> {_, Schema_ref} = Entry, schema_has_optional_fields(Schema_ref, Ctx) end ), Imports = case Needs_option of true -> [<<"gleam/option.{type Option}"/utf8>>]; false -> [] end, Sb = begin _pipe = oaspec@util@string_extra:file_header(<<"0.3.0"/utf8>>), oaspec@util@string_extra:imports(_pipe, Imports) end, Sb@2 = gleam@list:fold( Schemas, Sb, fun(Sb@1, Entry@1) -> {Name, Schema_ref@1} = Entry@1, generate_inline_enums_for_schema(Sb@1, Name, Schema_ref@1, Ctx) end ), Sb@4 = gleam@list:fold( Schemas, Sb@2, fun(Sb@3, Entry@2) -> {Name@1, Schema_ref@2} = Entry@2, generate_type_def(Sb@3, Name@1, Schema_ref@2, Ctx) end ), Sb@5 = generate_anonymous_types(Sb@4, Ctx), oaspec@util@string_extra:to_string(Sb@5). -file("src/oaspec/codegen/types.gleam", 17). ?DOC(" Generate type definitions from OpenAPI schemas.\n"). -spec generate(oaspec@codegen@context:context()) -> list(oaspec@codegen@context:generated_file()). generate(Ctx) -> Types_content = generate_types(Ctx), Request_types_content = generate_request_types(Ctx), Response_types_content = generate_response_types(Ctx), [{generated_file, <<"types.gleam"/utf8>>, Types_content}, {generated_file, <<"request_types.gleam"/utf8>>, Request_types_content}, {generated_file, <<"response_types.gleam"/utf8>>, Response_types_content}].