-module(oaspec@codegen@decoders). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/codegen/decoders.gleam"). -export([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/decoders.gleam", 241). ?DOC(" Convert a SchemaRef to a decoder expression string.\n"). -spec schema_ref_to_decoder( oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> binary(). schema_ref_to_decoder(Ref, Ctx) -> _ = Ctx, case Ref of {inline, {string_schema, _, _, _, _, _, _, _}} -> <<"decode.string"/utf8>>; {inline, {integer_schema, _, _, _, _, _}} -> <<"decode.int"/utf8>>; {inline, {number_schema, _, _, _, _, _}} -> <<"decode.float"/utf8>>; {inline, {boolean_schema, _, _}} -> <<"decode.bool"/utf8>>; {inline, {array_schema, _, Items, _, _, _}} -> Inner = schema_ref_to_decoder(Items, Ctx), <<<<"decode.list("/utf8, Inner/binary>>/binary, ")"/utf8>>; {reference, Ref@1} -> Name = oaspec@openapi@resolver:ref_to_name(Ref@1), <<(oaspec@util@naming:to_snake_case(Name))/binary, "_decoder()"/utf8>>; _ -> <<"decode.string"/utf8>> end. -file("src/oaspec/codegen/decoders.gleam", 261). ?DOC(" Check if a SchemaRef has nullable: true.\n"). -spec schema_ref_is_nullable(oaspec@openapi@schema:schema_ref()) -> boolean(). schema_ref_is_nullable(Ref) -> case Ref of {inline, Schema} -> oaspec@openapi@schema:is_nullable(Schema); {reference, _} -> false end. -file("src/oaspec/codegen/decoders.gleam", 457). ?DOC( " Convert a SchemaRef to a json.Json encoder function reference.\n" " Used for json.nullable(value, ) and json.array(list, ).\n" ). -spec schema_ref_to_json_encoder_fn( oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> binary(). schema_ref_to_json_encoder_fn(Ref, Ctx) -> _ = Ctx, case Ref of {inline, {string_schema, _, _, _, _, _, _, _}} -> <<"json.string"/utf8>>; {inline, {integer_schema, _, _, _, _, _}} -> <<"json.int"/utf8>>; {inline, {number_schema, _, _, _, _, _}} -> <<"json.float"/utf8>>; {inline, {boolean_schema, _, _}} -> <<"json.bool"/utf8>>; {reference, Ref@1} -> Name = oaspec@openapi@resolver:ref_to_name(Ref@1), <<<<"encode_"/utf8, (oaspec@util@naming:to_snake_case(Name))/binary>>/binary, "_json"/utf8>>; _ -> <<"json.string"/utf8>> end. -file("src/oaspec/codegen/decoders.gleam", 433). ?DOC( " Convert a SchemaRef to a json.Json encoder expression.\n" " Returns an expression that produces json.Json (not String).\n" ). -spec schema_ref_to_json_encoder( binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> binary(). schema_ref_to_json_encoder(Value_expr, Ref, Ctx) -> case Ref of {inline, {string_schema, _, _, _, _, _, _, _}} -> <<<<"json.string("/utf8, Value_expr/binary>>/binary, ")"/utf8>>; {inline, {integer_schema, _, _, _, _, _}} -> <<<<"json.int("/utf8, Value_expr/binary>>/binary, ")"/utf8>>; {inline, {number_schema, _, _, _, _, _}} -> <<<<"json.float("/utf8, Value_expr/binary>>/binary, ")"/utf8>>; {inline, {boolean_schema, _, _}} -> <<<<"json.bool("/utf8, Value_expr/binary>>/binary, ")"/utf8>>; {inline, {array_schema, _, Items, _, _, _}} -> Inner_fn = schema_ref_to_json_encoder_fn(Items, Ctx), <<<<<<<<"json.array("/utf8, Value_expr/binary>>/binary, ", "/utf8>>/binary, Inner_fn/binary>>/binary, ")"/utf8>>; {reference, Ref@1} -> Name = oaspec@openapi@resolver:ref_to_name(Ref@1), <<<<<<<<"encode_"/utf8, (oaspec@util@naming:to_snake_case(Name))/binary>>/binary, "_json("/utf8>>/binary, Value_expr/binary>>/binary, ")"/utf8>>; _ -> <<<<"json.string("/utf8, Value_expr/binary>>/binary, ")"/utf8>> end. -file("src/oaspec/codegen/decoders.gleam", 299). ?DOC( " Generate an encoder function for a schema.\n" " Each type gets two functions:\n" " encode_x_json(value) -> json.Json (for composition in objects)\n" " encode_x(value) -> String (for standalone use)\n" ). -spec generate_encoder( gleam@string_tree:string_tree(), binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_encoder(Sb, Name, Schema_ref, Ctx) -> Type_name = oaspec@util@naming:schema_to_type_name(Name), Fn_name = <<"encode_"/utf8, (oaspec@util@naming:to_snake_case(Name))/binary>>, Json_fn_name = <>, case Schema_ref of {inline, {object_schema, _, Properties, Required, _, _, _}} -> Sb@1 = begin _pipe = Sb, _pipe@1 = oaspec@util@string_extra:line( _pipe, <<<<<<<<"pub fn "/utf8, Json_fn_name/binary>>/binary, "(value: types."/utf8>>/binary, Type_name/binary>>/binary, ") -> json.Json {"/utf8>> ), oaspec@util@string_extra:indent( _pipe@1, 1, <<"json.object(["/utf8>> ) end, Props = maps:to_list(Properties), Sb@3 = gleam@list:index_fold( Props, Sb@1, fun(Sb@2, Entry, Idx) -> {Prop_name, Prop_ref} = Entry, Field_name = oaspec@util@naming:to_snake_case(Prop_name), Is_required = gleam@list:contains(Required, Prop_name), Trailing = case Idx =:= (erlang:length(Props) - 1) of true -> <<""/utf8>>; false -> <<","/utf8>> end, Encoder_expr = schema_ref_to_json_encoder( <<"value."/utf8, Field_name/binary>>, Prop_ref, Ctx ), case Is_required of true -> _pipe@2 = Sb@2, oaspec@util@string_extra:indent( _pipe@2, 2, <<<<<<<<<<"#(\""/utf8, Prop_name/binary>>/binary, "\", "/utf8>>/binary, Encoder_expr/binary>>/binary, ")"/utf8>>/binary, Trailing/binary>> ); false -> _pipe@3 = Sb@2, oaspec@util@string_extra:indent( _pipe@3, 2, <<<<<<<<<<<<<<"#(\""/utf8, Prop_name/binary>>/binary, "\", json.nullable(value."/utf8>>/binary, Field_name/binary>>/binary, ", "/utf8>>/binary, (schema_ref_to_json_encoder_fn( Prop_ref, Ctx ))/binary>>/binary, "))"/utf8>>/binary, Trailing/binary>> ) end end ), Sb@4 = begin _pipe@4 = Sb@3, _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 1, <<"])"/utf8>> ), _pipe@6 = oaspec@util@string_extra:line(_pipe@5, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@6) end, Sb@5 = begin _pipe@7 = Sb@4, _pipe@8 = oaspec@util@string_extra:line( _pipe@7, <<<<<<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: types."/utf8>>/binary, Type_name/binary>>/binary, ") -> String {"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 1, < json.to_string()"/utf8>> ), _pipe@10 = oaspec@util@string_extra:line(_pipe@9, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@10) end, Sb@5; {inline, {string_schema, _, _, Enum_values, _, _, _, _}} when Enum_values =/= [] -> Sb@6 = begin _pipe@11 = Sb, _pipe@12 = oaspec@util@string_extra:line( _pipe@11, <<<<<<<<"pub fn "/utf8, Json_fn_name/binary>>/binary, "(value: types."/utf8>>/binary, Type_name/binary>>/binary, ") -> json.Json {"/utf8>> ), oaspec@util@string_extra:indent( _pipe@12, 1, <<"let str = case value {"/utf8>> ) end, Sb@8 = gleam@list:fold( Enum_values, Sb@6, fun(Sb@7, Value) -> Variant = oaspec@util@naming:schema_to_type_name( <<<>/binary, Value/binary>> ), _pipe@13 = Sb@7, oaspec@util@string_extra:indent( _pipe@13, 2, <<<<<<<<"types."/utf8, Variant/binary>>/binary, " -> \""/utf8>>/binary, Value/binary>>/binary, "\""/utf8>> ) end ), Sb@9 = begin _pipe@14 = Sb@8, _pipe@15 = oaspec@util@string_extra:indent( _pipe@14, 1, <<"}"/utf8>> ), _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 1, <<"json.string(str)"/utf8>> ), _pipe@17 = oaspec@util@string_extra:line(_pipe@16, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@17) end, Sb@10 = begin _pipe@18 = Sb@9, _pipe@19 = oaspec@util@string_extra:line( _pipe@18, <<<<<<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: types."/utf8>>/binary, Type_name/binary>>/binary, ") -> String {"/utf8>> ), _pipe@20 = oaspec@util@string_extra:indent( _pipe@19, 1, < json.to_string()"/utf8>> ), _pipe@21 = oaspec@util@string_extra:line(_pipe@20, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@21) end, Sb@10; _ -> Sb end. -file("src/oaspec/codegen/decoders.gleam", 273). ?DOC(" Generate JSON encoders for all component schemas.\n"). -spec generate_encoders(oaspec@codegen@context:context()) -> binary(). generate_encoders(Ctx) -> Sb = begin _pipe = oaspec@util@string_extra:file_header(<<"0.1.2"/utf8>>), oaspec@util@string_extra:imports( _pipe, [<<"gleam/json"/utf8>>, <<(erlang:element(5, erlang:element(3, Ctx)))/binary, "/types"/utf8>>] ) end, Schemas = case erlang:element(5, erlang:element(2, Ctx)) of {some, Components} -> maps:to_list(erlang:element(2, Components)); none -> [] end, Sb@2 = gleam@list:fold( Schemas, Sb, fun(Sb@1, Entry) -> {Name, Schema_ref} = Entry, generate_encoder(Sb@1, Name, Schema_ref, Ctx) end ), oaspec@util@string_extra:to_string(Sb@2). -file("src/oaspec/codegen/decoders.gleam", 473). ?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/decoders.gleam", 54). ?DOC(" Generate decoder functions for a schema.\n"). -spec generate_decoder( gleam@string_tree:string_tree(), binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_decoder(Sb, Name, Schema_ref, Ctx) -> Type_name = oaspec@util@naming:schema_to_type_name(Name), Fn_name = <<"decode_"/utf8, (oaspec@util@naming:to_snake_case(Name))/binary>>, Decoder_fn_name = <<(oaspec@util@naming:to_snake_case(Name))/binary, "_decoder"/utf8>>, case Schema_ref of {inline, {object_schema, Description, Properties, Required, _, _, Nullable}} -> Sb@1 = maybe_doc_comment(Sb, Description), Sb@2 = begin _pipe = Sb@1, oaspec@util@string_extra:line( _pipe, <<<<<<<<"pub fn "/utf8, Decoder_fn_name/binary>>/binary, "() -> decode.Decoder(types."/utf8>>/binary, Type_name/binary>>/binary, ") {"/utf8>> ) end, Props = maps:to_list(Properties), Sb@4 = gleam@list:fold( Props, Sb@2, fun(Sb@3, Entry) -> {Prop_name, Prop_ref} = Entry, Field_name = oaspec@util@naming:to_snake_case(Prop_name), Is_required = gleam@list:contains(Required, Prop_name), Field_decoder = schema_ref_to_decoder(Prop_ref, Ctx), Is_nullable_schema = schema_ref_is_nullable(Prop_ref), case Is_required of true -> _pipe@1 = Sb@3, oaspec@util@string_extra:indent( _pipe@1, 1, <<<<<<<<<<<<"use "/utf8, Field_name/binary>>/binary, " <- decode.field(\""/utf8>>/binary, Prop_name/binary>>/binary, "\", "/utf8>>/binary, Field_decoder/binary>>/binary, ")"/utf8>> ); false -> case Is_nullable_schema of true -> _pipe@2 = Sb@3, oaspec@util@string_extra:indent( _pipe@2, 1, <<<<<<<<<<<<"use "/utf8, Field_name/binary>>/binary, " <- decode.optional_field(\""/utf8>>/binary, Prop_name/binary>>/binary, "\", option.None, "/utf8>>/binary, Field_decoder/binary>>/binary, ")"/utf8>> ); false -> _pipe@3 = Sb@3, oaspec@util@string_extra:indent( _pipe@3, 1, <<<<<<<<<<<<"use "/utf8, Field_name/binary>>/binary, " <- decode.optional_field(\""/utf8>>/binary, Prop_name/binary>>/binary, "\", option.None, decode.optional("/utf8>>/binary, Field_decoder/binary>>/binary, "))"/utf8>> ) end end end ), Param_names = gleam@list:map( Props, fun(Entry@1) -> {Prop_name@1, _} = Entry@1, Field_name@1 = oaspec@util@naming:to_snake_case(Prop_name@1), <<<>/binary, Field_name@1/binary>> end ), Sb@5 = begin _pipe@4 = Sb@4, oaspec@util@string_extra:indent( _pipe@4, 1, <<<<<<<<"decode.success(types."/utf8, Type_name/binary>>/binary, "("/utf8>>/binary, (oaspec@util@string_extra:join_with( Param_names, <<", "/utf8>> ))/binary>>/binary, "))"/utf8>> ) end, Sb@6 = begin _pipe@5 = Sb@5, _pipe@6 = oaspec@util@string_extra:line(_pipe@5, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@6) end, Sb@7 = begin _pipe@7 = Sb@6, _pipe@8 = oaspec@util@string_extra:line( _pipe@7, <<<<<<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(json_string: String) -> Result(types."/utf8>>/binary, Type_name/binary>>/binary, ", json.DecodeError) {"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 1, <<<<"json.parse(json_string, "/utf8, Decoder_fn_name/binary>>/binary, "())"/utf8>> ), _pipe@10 = oaspec@util@string_extra:line(_pipe@9, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@10) end, _ = Nullable, Sb@7; {inline, {string_schema, Description@1, _, Enum_values, _, _, _, _}} when Enum_values =/= [] -> Sb@8 = maybe_doc_comment(Sb, Description@1), Sb@9 = begin _pipe@11 = Sb@8, _pipe@12 = oaspec@util@string_extra:line( _pipe@11, <<<<<<<<"pub fn "/utf8, Decoder_fn_name/binary>>/binary, "() -> decode.Decoder(types."/utf8>>/binary, Type_name/binary>>/binary, ") {"/utf8>> ), _pipe@13 = oaspec@util@string_extra:indent( _pipe@12, 1, <<"use value <- decode.then(decode.string)"/utf8>> ), oaspec@util@string_extra:indent( _pipe@13, 1, <<"case value {"/utf8>> ) end, Sb@11 = gleam@list:fold( Enum_values, Sb@9, fun(Sb@10, Value) -> Variant = oaspec@util@naming:schema_to_type_name( <<<>/binary, Value/binary>> ), _pipe@14 = Sb@10, oaspec@util@string_extra:indent( _pipe@14, 2, <<<<<<<<"\""/utf8, Value/binary>>/binary, "\" -> decode.success(types."/utf8>>/binary, Variant/binary>>/binary, ")"/utf8>> ) end ), Sb@12 = begin _pipe@15 = Sb@11, _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 2, <<<<<<<<"_ -> decode.failure(types."/utf8, (oaspec@util@naming:schema_to_type_name( <<<>/binary, ((case Enum_values of [First | _] -> First; [] -> <<"unknown"/utf8>> end))/binary>> ))/binary>>/binary, ", \""/utf8>>/binary, Type_name/binary>>/binary, "\")"/utf8>> ), _pipe@17 = oaspec@util@string_extra:indent( _pipe@16, 1, <<"}"/utf8>> ), _pipe@18 = oaspec@util@string_extra:line(_pipe@17, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@18) end, Sb@13 = begin _pipe@19 = Sb@12, _pipe@20 = oaspec@util@string_extra:line( _pipe@19, <<<<<<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(json_string: String) -> Result(types."/utf8>>/binary, Type_name/binary>>/binary, ", json.DecodeError) {"/utf8>> ), _pipe@21 = oaspec@util@string_extra:indent( _pipe@20, 1, <<<<"json.parse(json_string, "/utf8, Decoder_fn_name/binary>>/binary, "())"/utf8>> ), _pipe@22 = oaspec@util@string_extra:line(_pipe@21, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@22) end, Sb@13; _ -> Sb end. -file("src/oaspec/codegen/decoders.gleam", 29). ?DOC(" Generate JSON decoders for all component schemas.\n"). -spec generate_decoders(oaspec@codegen@context:context()) -> binary(). generate_decoders(Ctx) -> Sb = begin _pipe = oaspec@util@string_extra:file_header(<<"0.1.2"/utf8>>), oaspec@util@string_extra:imports( _pipe, [<<"gleam/dynamic/decode"/utf8>>, <<"gleam/json"/utf8>>, <<"gleam/option"/utf8>>, <<(erlang:element(5, erlang:element(3, Ctx)))/binary, "/types"/utf8>>] ) end, Schemas = case erlang:element(5, erlang:element(2, Ctx)) of {some, Components} -> maps:to_list(erlang:element(2, Components)); none -> [] end, Sb@2 = gleam@list:fold( Schemas, Sb, fun(Sb@1, Entry) -> {Name, Schema_ref} = Entry, generate_decoder(Sb@1, Name, Schema_ref, Ctx) end ), oaspec@util@string_extra:to_string(Sb@2). -file("src/oaspec/codegen/decoders.gleam", 14). ?DOC(" Generate decoder and encoder modules.\n"). -spec generate(oaspec@codegen@context:context()) -> list(oaspec@codegen@context:generated_file()). generate(Ctx) -> Decode_content = generate_decoders(Ctx), Encode_content = generate_encoders(Ctx), [{generated_file, <<"decode.gleam"/utf8>>, Decode_content}, {generated_file, <<"encode.gleam"/utf8>>, Encode_content}].