-module(oaspec@codegen@ir_build). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/codegen/ir_build.gleam"). -export([sorted_entries/1, is_internal_schema/1, build_types_module/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/ir_build.gleam", 68). -spec compute_imports( list({binary(), oaspec@openapi@schema:schema_ref()}), oaspec@codegen@context:context() ) -> list(binary()). compute_imports(Schemas, Ctx) -> Needs_option = gleam@list:any( Schemas, fun(Entry) -> {_, Schema_ref} = Entry, case Schema_ref of {inline, {any_of_schema, _, _, _}} -> true; _ -> oaspec@codegen@schema_utils:schema_has_optional_fields( Schema_ref, Ctx ) end end ), Needs_dict = gleam@list:any( Schemas, fun(Entry@1) -> {_, Schema_ref@1} = Entry@1, oaspec@codegen@schema_utils:schema_has_additional_properties( Schema_ref@1, Ctx ) end ), Needs_dynamic = gleam@list:any( Schemas, fun(Entry@2) -> {_, Schema_ref@2} = Entry@2, oaspec@codegen@schema_utils:schema_has_untyped_additional_properties( Schema_ref@2, Ctx ) end ), case {Needs_option, Needs_dict, Needs_dynamic} of {true, true, true} -> [<<"gleam/dict.{type Dict}"/utf8>>, <<"gleam/dynamic.{type Dynamic}"/utf8>>, <<"gleam/option.{type Option}"/utf8>>]; {true, true, false} -> [<<"gleam/dict.{type Dict}"/utf8>>, <<"gleam/option.{type Option}"/utf8>>]; {true, false, _} -> [<<"gleam/option.{type Option}"/utf8>>]; {false, true, true} -> [<<"gleam/dict.{type Dict}"/utf8>>, <<"gleam/dynamic.{type Dynamic}"/utf8>>]; {false, true, false} -> [<<"gleam/dict.{type Dict}"/utf8>>]; {false, false, _} -> [] end. -file("src/oaspec/codegen/ir_build.gleam", 481). -spec schema_ref_to_type( oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> binary(). schema_ref_to_type(Ref, _) -> case Ref of {inline, S} -> oaspec@codegen@schema_dispatch:schema_type(S); {reference, _, Name} -> oaspec@util@naming:schema_to_type_name(Name) end. -file("src/oaspec/codegen/ir_build.gleam", 466). -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/ir_build.gleam", 491). ?DOC( " Sort dict entries by key for deterministic output ordering.\n" " Gleam Dict does not guarantee iteration order, so all codegen paths\n" " that produce output from dict entries must sort first.\n" ). -spec sorted_entries(gleam@dict:dict(binary(), ION)) -> list({binary(), ION}). sorted_entries(D) -> _pipe = maps:to_list(D), gleam@list:sort( _pipe, fun(A, B) -> gleam@string:compare(erlang:element(1, A), erlang:element(1, B)) end ). -file("src/oaspec/codegen/ir_build.gleam", 133). -spec inline_enums_from_properties( binary(), gleam@dict:dict(binary(), oaspec@openapi@schema:schema_ref()), oaspec@codegen@context:context() ) -> list(oaspec@codegen@ir:declaration()). inline_enums_from_properties(Parent_name, Properties, _) -> Entries = sorted_entries(Properties), gleam@list:filter_map( Entries, fun(Entry) -> {Prop_name, Prop_ref} = Entry, case Prop_ref of {inline, {string_schema, Metadata, _, 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>>, Deduped_variants = oaspec@openapi@dedup:dedup_enum_variants( Enum_values ), Variants = begin _pipe = gleam@list:zip(Enum_values, Deduped_variants), gleam@list:map( _pipe, fun(Pair) -> {_, Variant_suffix} = Pair, <<(oaspec@util@naming:schema_to_type_name( Type_name ))/binary, Variant_suffix/binary>> end ) end, {ok, {declaration, erlang:element(2, Metadata), {enum_type, Type_name, Variants}}}; _ -> {error, nil} end end ). -file("src/oaspec/codegen/ir_build.gleam", 117). -spec inline_enums_for_schema( binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> list(oaspec@codegen@ir:declaration()). inline_enums_for_schema(Parent_name, Schema_ref, Ctx) -> case Schema_ref of {inline, {object_schema, _, Properties, _, _, _, _}} -> inline_enums_from_properties(Parent_name, Properties, Ctx); {inline, {all_of_schema, _, Schemas}} -> Merged = oaspec@codegen@allof_merge:merge_allof_schemas( Schemas, Ctx ), inline_enums_from_properties( Parent_name, erlang:element(2, Merged), Ctx ); _ -> [] end. -file("src/oaspec/codegen/ir_build.gleam", 187). -spec schema_type_decls( binary(), binary(), oaspec@openapi@schema:schema_object(), oaspec@codegen@context:context() ) -> list(oaspec@codegen@ir:declaration()). schema_type_decls(Type_name, Raw_name, Schema, Ctx) -> case Schema of {object_schema, Metadata, Properties, Required, Additional_properties, _, _} -> Props = sorted_entries(Properties), Deduped_names = oaspec@openapi@dedup:dedup_property_names( gleam@list:map(Props, fun(E) -> erlang:element(1, E) end) ), Fields = begin _pipe = gleam@list:zip(Props, Deduped_names), gleam@list:map( _pipe, fun(Pair) -> {Entry, Field_name} = Pair, {Prop_name, Prop_ref} = Entry, 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 = oaspec@codegen@schema_utils: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, {field, Field_name, Final_type} end ) end, Fields@1 = case Additional_properties of {typed, Ap_ref} -> Inner_type = schema_ref_to_type(Ap_ref, Ctx), lists:append( Fields, [{field, <<"additional_properties"/utf8>>, <<<<"Dict(String, "/utf8, Inner_type/binary>>/binary, ")"/utf8>>}] ); untyped -> lists:append( Fields, [{field, <<"additional_properties"/utf8>>, <<"Dict(String, Dynamic)"/utf8>>}] ); forbidden -> Fields end, [{declaration, erlang:element(2, Metadata), {record_type, Type_name, Fields@1}}]; {string_schema, Metadata@1, _, Enum_values, _, _, _} when Enum_values =/= [] -> Deduped_variants = oaspec@openapi@dedup:dedup_enum_variants( Enum_values ), Variants = begin _pipe@1 = gleam@list:zip(Enum_values, Deduped_variants), gleam@list:map( _pipe@1, fun(Pair@1) -> {_, Variant_suffix} = Pair@1, <<(oaspec@util@naming:schema_to_type_name(Type_name))/binary, Variant_suffix/binary>> end ) end, [{declaration, erlang:element(2, Metadata@1), {enum_type, Type_name, Variants}}]; {one_of_schema, Metadata@2, Schemas, _} -> Variants@1 = gleam@list:map( Schemas, fun(S_ref) -> Variant_type = schema_ref_to_type(S_ref, Ctx), Variant_name = <>, {variant_with_type, Variant_name, Variant_type} end ), [{declaration, erlang:element(2, Metadata@2), {union_type, Type_name, Variants@1}}]; {any_of_schema, Metadata@3, Schemas@1, _} -> Fields@2 = gleam@list:map( Schemas@1, fun(S_ref@1) -> Variant_type@1 = schema_ref_to_type(S_ref@1, Ctx), Field_name@1 = oaspec@util@naming:to_snake_case( Variant_type@1 ), {field, Field_name@1, <<<<"Option("/utf8, Variant_type@1/binary>>/binary, ")"/utf8>>} end ), [{declaration, erlang:element(2, Metadata@3), {record_type, Type_name, Fields@2}}]; {all_of_schema, Metadata@4, Schemas@2} -> Merged = oaspec@codegen@allof_merge:merge_allof_schemas( Schemas@2, Ctx ), Merged_schema = {object_schema, Metadata@4, erlang:element(2, Merged), erlang:element(3, Merged), erlang:element(4, Merged), none, none}, schema_type_decls(Type_name, Raw_name, Merged_schema, Ctx); _ -> Gleam_type = oaspec@codegen@schema_dispatch:schema_type(Schema), [{declaration, none, {type_alias, Type_name, Gleam_type}}] end. -file("src/oaspec/codegen/ir_build.gleam", 167). -spec type_def_decls( binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> list(oaspec@codegen@ir:declaration()). type_def_decls(Name, Schema_ref, Ctx) -> Type_name = oaspec@util@naming:schema_to_type_name(Name), case Schema_ref of {inline, Schema} -> schema_type_decls(Type_name, Name, Schema, Ctx); {reference, _, Ref_name} -> Resolved_type = oaspec@util@naming:schema_to_type_name(Ref_name), [{declaration, none, {type_alias, Type_name, Resolved_type}}] end. -file("src/oaspec/codegen/ir_build.gleam", 407). -spec anonymous_type_for_schema( binary(), binary(), oaspec@openapi@schema:schema_object(), oaspec@codegen@context:context() ) -> list(oaspec@codegen@ir:declaration()). anonymous_type_for_schema(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, _, _, _, _, _, _} -> schema_type_decls(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 -> Variants = gleam@list:map( Schemas, fun(S_ref) -> Variant_type = schema_ref_to_type(S_ref, Ctx), Variant_name = <>, {variant_with_type, Variant_name, Variant_type} end ), [{declaration, none, {union_type, Type_name, Variants}}]; false -> [] end; {any_of_schema, _, _, _} -> schema_type_decls(Type_name, Raw_name, Schema_obj, Ctx); {all_of_schema, Metadata, Schemas@1} -> Merged = oaspec@codegen@allof_merge:merge_allof_schemas( Schemas@1, Ctx ), Merged_schema = {object_schema, Metadata, erlang:element(2, Merged), erlang:element(3, Merged), erlang:element(4, Merged), none, none}, schema_type_decls(Type_name, Raw_name, Merged_schema, Ctx); _ -> [] end. -file("src/oaspec/codegen/ir_build.gleam", 343). -spec anonymous_response_type_decls( binary(), oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved()), oaspec@codegen@context:context() ) -> list(oaspec@codegen@ir:declaration()). anonymous_response_type_decls(Op_id, Operation, Ctx) -> Responses = oaspec@util@http:sort_response_entries( maps:to_list(erlang:element(8, Operation)) ), gleam@list:flat_map( Responses, fun(Entry) -> {Status_code, Ref_or} = Entry, case Ref_or of {value, Response} -> Content_entries = sorted_entries( erlang:element(3, Response) ), case Content_entries of [{_, Media_type} | _] -> case erlang:element(2, Media_type) of {some, {inline, Schema_obj}} -> Filtered_schema = oaspec@codegen@schema_utils:filter_write_only_properties( Schema_obj, Ctx ), anonymous_type_for_schema( Op_id, <<"Response"/utf8, (oaspec@util@http:status_code_suffix( Status_code ))/binary>>, Filtered_schema, Ctx ); _ -> [] end; _ -> [] end; _ -> [] end end ). -file("src/oaspec/codegen/ir_build.gleam", 377). -spec anonymous_request_body_type_decls( binary(), oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved()), oaspec@codegen@context:context() ) -> list(oaspec@codegen@ir:declaration()). anonymous_request_body_type_decls(Op_id, Operation, Ctx) -> case erlang:element(7, Operation) of {some, {value, Rb}} -> Content_entries = sorted_entries(erlang:element(3, Rb)), case Content_entries of [{_, Media_type} | _] -> case erlang:element(2, Media_type) of {some, {inline, Schema_obj}} -> Filtered_schema = oaspec@codegen@schema_utils:filter_read_only_properties( Schema_obj, Ctx ), anonymous_type_for_schema( Op_id, <<"RequestBody"/utf8>>, Filtered_schema, Ctx ); _ -> [] end; _ -> [] end; _ -> [] end. -file("src/oaspec/codegen/ir_build.gleam", 328). -spec anonymous_type_decls(oaspec@codegen@context:context()) -> list(oaspec@codegen@ir:declaration()). anonymous_type_decls(Ctx) -> Operations = oaspec@openapi@operations:collect_operations(Ctx), gleam@list:flat_map( Operations, fun(Op) -> {Op_id, Operation, _, _} = Op, Response_decls = anonymous_response_type_decls( Op_id, Operation, Ctx ), Request_decls = anonymous_request_body_type_decls( Op_id, Operation, Ctx ), lists:append(Response_decls, Request_decls) end ). -file("src/oaspec/codegen/ir_build.gleam", 496). ?DOC(" Check if a schema ref is marked as internal (allOf helper type).\n"). -spec is_internal_schema(oaspec@openapi@schema:schema_ref()) -> boolean(). is_internal_schema(Schema_ref) -> case Schema_ref of {inline, Obj} -> erlang:element(13, oaspec@openapi@schema:get_metadata(Obj)); _ -> false end. -file("src/oaspec/codegen/ir_build.gleam", 28). ?DOC(" Build an IR Module for the types.gleam file from component schemas.\n"). -spec build_types_module(oaspec@codegen@context:context()) -> oaspec@codegen@ir:module_(). build_types_module(Ctx) -> Schemas = case erlang:element(5, erlang:element(2, Ctx)) of {some, Components} -> _pipe = 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 ), gleam@list:filter( _pipe, fun(Entry) -> not is_internal_schema(erlang:element(2, Entry)) end ); none -> [] end, Imports = compute_imports(Schemas, Ctx), Inline_enum_decls = gleam@list:flat_map( Schemas, fun(Entry@1) -> {Name, Schema_ref} = Entry@1, inline_enums_for_schema(Name, Schema_ref, Ctx) end ), Main_decls = gleam@list:flat_map( Schemas, fun(Entry@2) -> {Name@1, Schema_ref@1} = Entry@2, type_def_decls(Name@1, Schema_ref@1, Ctx) end ), Anon_decls = anonymous_type_decls(Ctx), {module, <<""/utf8>>, Imports, lists:append([Inline_enum_decls, Main_decls, Anon_decls])}.