Current section

Files

Jump to
oaspec src oaspec@codegen@server.erl
Raw

src/oaspec@codegen@server.erl

-module(oaspec@codegen@server).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/oaspec/codegen/server.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/server.gleam", 60).
?DOC(" Generate a single handler stub.\n").
-spec generate_handler(
gleam@string_tree:string_tree(),
binary(),
oaspec@openapi@spec:operation(),
oaspec@codegen@context:context()
) -> gleam@string_tree:string_tree().
generate_handler(Sb, Op_id, Operation, _) ->
Fn_name = oaspec@util@naming:operation_to_function_name(Op_id),
Request_type = <<(oaspec@util@naming:schema_to_type_name(Op_id))/binary,
"Request"/utf8>>,
Response_type = <<(oaspec@util@naming:schema_to_type_name(Op_id))/binary,
"Response"/utf8>>,
Sb@1 = case erlang:element(3, Operation) of
{some, Summary} ->
_pipe = Sb,
oaspec@util@string_extra:doc_comment(_pipe, Summary);
_ ->
Sb
end,
Sb@2 = case erlang:element(4, Operation) of
{some, Desc} ->
_pipe@1 = Sb@1,
oaspec@util@string_extra:doc_comment(_pipe@1, Desc);
_ ->
Sb@1
end,
Has_params = not gleam@list:is_empty(erlang:element(6, Operation)) orelse gleam@option:is_some(
erlang:element(7, Operation)
),
Sb@3 = case Has_params of
true ->
_pipe@2 = Sb@2,
oaspec@util@string_extra:line(
_pipe@2,
<<<<<<<<<<<<"pub fn "/utf8, Fn_name/binary>>/binary,
"(req: request_types."/utf8>>/binary,
Request_type/binary>>/binary,
") -> response_types."/utf8>>/binary,
Response_type/binary>>/binary,
" {"/utf8>>
);
false ->
_pipe@3 = Sb@2,
oaspec@util@string_extra:line(
_pipe@3,
<<<<<<<<"pub fn "/utf8, Fn_name/binary>>/binary,
"() -> response_types."/utf8>>/binary,
Response_type/binary>>/binary,
" {"/utf8>>
)
end,
Sb@4 = case Has_params of
true ->
_pipe@4 = Sb@3,
oaspec@util@string_extra:indent(_pipe@4, 1, <<"let _ = req"/utf8>>);
false ->
Sb@3
end,
_pipe@5 = Sb@4,
_pipe@6 = oaspec@util@string_extra:indent(
_pipe@5,
1,
<<"// TODO: Implement "/utf8, Fn_name/binary>>
),
_pipe@7 = oaspec@util@string_extra:indent(_pipe@6, 1, <<"todo"/utf8>>),
_pipe@8 = oaspec@util@string_extra:line(_pipe@7, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@8).
-file("src/oaspec/codegen/server.gleam", 147).
?DOC(" Extract a short suffix from a URL expression for function naming.\n").
-spec url_expression_to_suffix(binary()) -> binary().
url_expression_to_suffix(Url_expression) ->
Parts = gleam@string:split(Url_expression, <<"/"/utf8>>),
case gleam@list:last(Parts) of
{ok, Last} ->
_pipe = Last,
_pipe@1 = gleam@string:replace(_pipe, <<"{"/utf8>>, <<""/utf8>>),
_pipe@2 = gleam@string:replace(_pipe@1, <<"}"/utf8>>, <<""/utf8>>),
_pipe@3 = gleam@string:replace(_pipe@2, <<"$"/utf8>>, <<""/utf8>>),
gleam@string:replace(_pipe@3, <<"#"/utf8>>, <<""/utf8>>);
{error, _} ->
<<"handler"/utf8>>
end.
-file("src/oaspec/codegen/server.gleam", 115).
?DOC(" Generate callback handler stubs for an operation's callbacks.\n").
-spec generate_callback_handlers(
gleam@string_tree:string_tree(),
binary(),
oaspec@openapi@spec:operation()
) -> gleam@string_tree:string_tree().
generate_callback_handlers(Sb, Op_id, Operation) ->
Callbacks = maps:to_list(erlang:element(11, Operation)),
gleam@list:fold(
Callbacks,
Sb,
fun(Sb@1, Entry) ->
{Callback_name, Callback} = Entry,
Callback_entries = maps:to_list(erlang:element(2, Callback)),
gleam@list:fold(
Callback_entries,
Sb@1,
fun(Sb@2, Cb_entry) ->
{Url_expression, _} = Cb_entry,
Fn_name = <<<<<<<<(oaspec@util@naming:operation_to_function_name(
Op_id
))/binary,
"_callback_"/utf8>>/binary,
(oaspec@util@naming:to_snake_case(Callback_name))/binary>>/binary,
"_"/utf8>>/binary,
(oaspec@util@naming:to_snake_case(
url_expression_to_suffix(Url_expression)
))/binary>>,
_pipe = Sb@2,
_pipe@1 = oaspec@util@string_extra:doc_comment(
_pipe,
<<<<<<"Callback handler stub for "/utf8,
Callback_name/binary>>/binary,
" on "/utf8>>/binary,
Op_id/binary>>
),
_pipe@2 = oaspec@util@string_extra:doc_comment(
_pipe@1,
<<"URL: "/utf8, Url_expression/binary>>
),
_pipe@3 = oaspec@util@string_extra:line(
_pipe@2,
<<<<"pub fn "/utf8, Fn_name/binary>>/binary,
"() -> String {"/utf8>>
),
_pipe@4 = oaspec@util@string_extra:indent(
_pipe@3,
1,
<<"// TODO: Implement callback "/utf8,
Callback_name/binary>>
),
_pipe@5 = oaspec@util@string_extra:indent(
_pipe@4,
1,
<<"todo"/utf8>>
),
_pipe@6 = oaspec@util@string_extra:line(
_pipe@5,
<<"}"/utf8>>
),
oaspec@util@string_extra:blank_line(_pipe@6)
end
)
end
).
-file("src/oaspec/codegen/server.gleam", 33).
?DOC(" Generate handler stubs for all operations.\n").
-spec generate_handlers(oaspec@codegen@context:context()) -> binary().
generate_handlers(Ctx) ->
Sb = begin
_pipe = oaspec@util@string_extra:file_header(<<"0.5.0"/utf8>>),
oaspec@util@string_extra:imports(
_pipe,
[<<(erlang:element(5, erlang:element(3, Ctx)))/binary,
"/request_types"/utf8>>,
<<(erlang:element(5, erlang:element(3, Ctx)))/binary,
"/response_types"/utf8>>]
)
end,
Operations = oaspec@codegen@types:collect_operations(Ctx),
Sb@2 = gleam@list:fold(
Operations,
Sb,
fun(Sb@1, Op) ->
{Op_id, Operation, _, _} = Op,
generate_handler(Sb@1, Op_id, Operation, Ctx)
end
),
Sb@4 = gleam@list:fold(
Operations,
Sb@2,
fun(Sb@3, Op@1) ->
{Op_id@1, Operation@1, _, _} = Op@1,
generate_callback_handlers(Sb@3, Op_id@1, Operation@1)
end
),
oaspec@util@string_extra:to_string(Sb@4).
-file("src/oaspec/codegen/server.gleam", 460).
?DOC(" Generate parse expression for a path parameter (already bound as String).\n").
-spec param_parse_expr(binary(), oaspec@openapi@spec:parameter()) -> binary().
param_parse_expr(Var_name, Param) ->
case erlang:element(6, Param) of
{some, {inline, {integer_schema, _, _, _, _, _, _, _}}} ->
<<<<"{ let assert Ok(v) = int.parse("/utf8, Var_name/binary>>/binary,
") v }"/utf8>>;
{some, {inline, {number_schema, _, _, _, _, _, _, _}}} ->
<<Var_name/binary, " // TODO: Parse as Float"/utf8>>;
{some, {inline, {boolean_schema, _}}} ->
<<<<"case "/utf8, Var_name/binary>>/binary,
" { \"true\" -> True _ -> False }"/utf8>>;
_ ->
Var_name
end.
-file("src/oaspec/codegen/server.gleam", 477).
?DOC(" Generate expression for a required query parameter.\n").
-spec query_required_expr(binary(), oaspec@openapi@spec:parameter()) -> binary().
query_required_expr(Key, Param) ->
Base = <<<<"{ let assert Ok(v) = dict.get(query, \""/utf8, Key/binary>>/binary,
"\") v }"/utf8>>,
case erlang:element(6, Param) of
{some, {inline, {integer_schema, _, _, _, _, _, _, _}}} ->
<<<<"{ let assert Ok(v) = dict.get(query, \""/utf8, Key/binary>>/binary,
"\") let assert Ok(n) = int.parse(v) n }"/utf8>>;
{some, {inline, {boolean_schema, _}}} ->
<<<<"{ let assert Ok(v) = dict.get(query, \""/utf8, Key/binary>>/binary,
"\") case v { \"true\" -> True _ -> False } }"/utf8>>;
_ ->
Base
end.
-file("src/oaspec/codegen/server.gleam", 493).
?DOC(" Generate expression for an optional query parameter.\n").
-spec query_optional_expr(binary(), oaspec@openapi@spec:parameter()) -> binary().
query_optional_expr(Key, Param) ->
case erlang:element(6, Param) of
{some, {inline, {integer_schema, _, _, _, _, _, _, _}}} ->
<<<<"case dict.get(query, \""/utf8, Key/binary>>/binary,
"\") { Ok(v) -> { case int.parse(v) { Ok(n) -> Some(n) _ -> None } } _ -> None }"/utf8>>;
{some, {inline, {boolean_schema, _}}} ->
<<<<"case dict.get(query, \""/utf8, Key/binary>>/binary,
"\") { Ok(v) -> Some(case v { \"true\" -> True _ -> False }) _ -> None }"/utf8>>;
_ ->
<<<<"case dict.get(query, \""/utf8, Key/binary>>/binary,
"\") { Ok(v) -> Some(v) _ -> None }"/utf8>>
end.
-file("src/oaspec/codegen/server.gleam", 509).
?DOC(" Generate expression for a required header parameter.\n").
-spec header_required_expr(binary(), oaspec@openapi@spec:parameter()) -> binary().
header_required_expr(Key, Param) ->
case erlang:element(6, Param) of
{some, {inline, {integer_schema, _, _, _, _, _, _, _}}} ->
<<<<"{ let assert Ok(v) = dict.get(headers, \""/utf8, Key/binary>>/binary,
"\") let assert Ok(n) = int.parse(v) n }"/utf8>>;
_ ->
<<<<"{ let assert Ok(v) = dict.get(headers, \""/utf8, Key/binary>>/binary,
"\") v }"/utf8>>
end.
-file("src/oaspec/codegen/server.gleam", 520).
?DOC(" Generate expression for an optional header parameter.\n").
-spec header_optional_expr(binary(), oaspec@openapi@spec:parameter()) -> binary().
header_optional_expr(Key, Param) ->
case erlang:element(6, Param) of
{some, {inline, {integer_schema, _, _, _, _, _, _, _}}} ->
<<<<"case dict.get(headers, \""/utf8, Key/binary>>/binary,
"\") { Ok(v) -> { case int.parse(v) { Ok(n) -> Some(n) _ -> None } } _ -> None }"/utf8>>;
_ ->
<<<<"case dict.get(headers, \""/utf8, Key/binary>>/binary,
"\") { Ok(v) -> Some(v) _ -> None }"/utf8>>
end.
-file("src/oaspec/codegen/server.gleam", 532).
?DOC(" Generate the body decode expression for a request body.\n").
-spec generate_body_decode_expr(oaspec@openapi@spec:request_body(), binary()) -> binary().
generate_body_decode_expr(Rb, Op_id) ->
Content_entries = maps:to_list(erlang:element(3, Rb)),
case Content_entries of
[{<<"application/json"/utf8>>, Media_type}] ->
Decode_fn = case erlang:element(2, Media_type) of
{some, {reference, _, Name}} ->
<<<<"decode.decode_"/utf8,
(oaspec@util@naming:to_snake_case(Name))/binary>>/binary,
"(body)"/utf8>>;
_ ->
<<<<"decode.decode_"/utf8,
(oaspec@util@naming:to_snake_case(Op_id))/binary>>/binary,
"_request_body(body)"/utf8>>
end,
case erlang:element(4, Rb) of
true ->
<<<<"{ let assert Ok(decoded) = "/utf8, Decode_fn/binary>>/binary,
" decoded }"/utf8>>;
false ->
<<<<"case body { \"\" -> None _ -> { case "/utf8,
Decode_fn/binary>>/binary,
" { Ok(decoded) -> Some(decoded) _ -> None } } }"/utf8>>
end;
_ ->
case erlang:element(4, Rb) of
true ->
<<"body"/utf8>>;
false ->
<<"case body { \"\" -> None _ -> Some(body) }"/utf8>>
end
end.
-file("src/oaspec/codegen/server.gleam", 706).
?DOC(" Get the encode function name for a schema reference.\n").
-spec get_encode_function(
gleam@option:option(oaspec@openapi@schema:schema_ref()),
oaspec@codegen@context:context()
) -> binary().
get_encode_function(Schema_ref, _) ->
case Schema_ref of
{some, {reference, _, Name}} ->
<<<<"encode.encode_"/utf8,
(oaspec@util@naming:to_snake_case(Name))/binary>>/binary,
"_json"/utf8>>;
{some, {inline, {array_schema, _, Items, _, _, _}}} ->
case Items of
{reference, _, Name@1} ->
<<<<"fn(items) { json.array(items, encode.encode_"/utf8,
(oaspec@util@naming:to_snake_case(Name@1))/binary>>/binary,
"_json) }"/utf8>>;
_ ->
<<"json.string"/utf8>>
end;
{some, {inline, {string_schema, _, _, _, _, _, _}}} ->
<<"json.string"/utf8>>;
{some, {inline, {integer_schema, _, _, _, _, _, _, _}}} ->
<<"json.int"/utf8>>;
{some, {inline, {number_schema, _, _, _, _, _, _, _}}} ->
<<"json.float"/utf8>>;
{some, {inline, {boolean_schema, _}}} ->
<<"json.bool"/utf8>>;
_ ->
<<"json.string"/utf8>>
end.
-file("src/oaspec/codegen/server.gleam", 562).
?DOC(" Generate code to convert a handler response to ServerResponse.\n").
-spec generate_response_conversion(
gleam@string_tree:string_tree(),
binary(),
oaspec@openapi@spec:operation(),
oaspec@codegen@context:context()
) -> gleam@string_tree:string_tree().
generate_response_conversion(Sb, Response_type_name, Operation, Ctx) ->
Responses = oaspec@util@http:sort_response_entries(
maps:to_list(erlang:element(8, Operation))
),
case gleam@list:is_empty(Responses) of
true ->
_pipe = Sb,
oaspec@util@string_extra:indent(
_pipe,
3,
<<"ServerResponse(status: 200, body: \"\", headers: [])"/utf8>>
);
false ->
Sb@1 = begin
_pipe@1 = Sb,
oaspec@util@string_extra:indent(
_pipe@1,
3,
<<"case response {"/utf8>>
)
end,
Sb@3 = gleam@list:fold(
Responses,
Sb@1,
fun(Sb@2, Entry) ->
{Status_code, Response} = Entry,
Variant_name = <<Response_type_name/binary,
(oaspec@util@http:status_code_suffix(Status_code))/binary>>,
Status_int = oaspec@util@http:status_code_to_int(
Status_code
),
Content_entries = maps:to_list(erlang:element(3, Response)),
case Content_entries of
[] ->
_pipe@2 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@2,
4,
<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
" -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: \"\", headers: [])"/utf8>>
);
[{Media_type_name, Media_type}] ->
case Media_type_name of
<<"application/json"/utf8>> ->
case erlang:element(2, Media_type) of
{some, _} ->
Encode_fn = get_encode_function(
erlang:element(2, Media_type),
Ctx
),
_pipe@3 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@3,
4,
<<<<<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
"(data) -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: json.to_string("/utf8>>/binary,
Encode_fn/binary>>/binary,
"(data)), headers: [#(\"content-type\", \"application/json\")])"/utf8>>
);
none ->
_pipe@4 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@4,
4,
<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
" -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: \"\", headers: [])"/utf8>>
)
end;
<<"text/plain"/utf8>> ->
case erlang:element(2, Media_type) of
{some, _} ->
_pipe@5 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@5,
4,
<<<<<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
"(data) -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: data, headers: [#(\"content-type\", \""/utf8>>/binary,
Media_type_name/binary>>/binary,
"\")])"/utf8>>
);
none ->
_pipe@6 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@6,
4,
<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
" -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: \"\", headers: [])"/utf8>>
)
end;
<<"application/xml"/utf8>> ->
case erlang:element(2, Media_type) of
{some, _} ->
_pipe@5 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@5,
4,
<<<<<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
"(data) -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: data, headers: [#(\"content-type\", \""/utf8>>/binary,
Media_type_name/binary>>/binary,
"\")])"/utf8>>
);
none ->
_pipe@6 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@6,
4,
<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
" -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: \"\", headers: [])"/utf8>>
)
end;
<<"text/xml"/utf8>> ->
case erlang:element(2, Media_type) of
{some, _} ->
_pipe@5 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@5,
4,
<<<<<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
"(data) -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: data, headers: [#(\"content-type\", \""/utf8>>/binary,
Media_type_name/binary>>/binary,
"\")])"/utf8>>
);
none ->
_pipe@6 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@6,
4,
<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
" -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: \"\", headers: [])"/utf8>>
)
end;
<<"application/octet-stream"/utf8>> ->
case erlang:element(2, Media_type) of
{some, _} ->
_pipe@5 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@5,
4,
<<<<<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
"(data) -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: data, headers: [#(\"content-type\", \""/utf8>>/binary,
Media_type_name/binary>>/binary,
"\")])"/utf8>>
);
none ->
_pipe@6 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@6,
4,
<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
" -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: \"\", headers: [])"/utf8>>
)
end;
_ ->
case erlang:element(2, Media_type) of
{some, _} ->
Encode_fn@1 = get_encode_function(
erlang:element(2, Media_type),
Ctx
),
_pipe@7 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@7,
4,
<<<<<<<<<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
"(data) -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: json.to_string("/utf8>>/binary,
Encode_fn@1/binary>>/binary,
"(data)), headers: [#(\"content-type\", \""/utf8>>/binary,
Media_type_name/binary>>/binary,
"\")])"/utf8>>
);
none ->
_pipe@8 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@8,
4,
<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
" -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: \"\", headers: [])"/utf8>>
)
end
end;
[_, _ | _] ->
_pipe@9 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@9,
4,
<<<<<<<<"response_types."/utf8,
Variant_name/binary>>/binary,
"(data) -> ServerResponse(status: "/utf8>>/binary,
Status_int/binary>>/binary,
", body: data, headers: [])"/utf8>>
)
end
end
),
_pipe@10 = Sb@3,
oaspec@util@string_extra:indent(_pipe@10, 3, <<"}"/utf8>>)
end.
-file("src/oaspec/codegen/server.gleam", 753).
?DOC(" Check if a path segment is a parameter.\n").
-spec is_path_param(binary()) -> boolean().
is_path_param(Segment) ->
case Segment of
<<"{"/utf8, _/binary>> ->
true;
_ ->
false
end.
-file("src/oaspec/codegen/server.gleam", 761).
?DOC(" Extract parameter name from {name}.\n").
-spec extract_param_name(binary()) -> binary().
extract_param_name(Segment) ->
_pipe = Segment,
_pipe@1 = gleam@string:replace(_pipe, <<"{"/utf8>>, <<""/utf8>>),
gleam@string:replace(_pipe@1, <<"}"/utf8>>, <<""/utf8>>).
-file("src/oaspec/codegen/server.gleam", 368).
?DOC(" Generate code to construct a typed request from raw inputs.\n").
-spec generate_request_construction(
gleam@string_tree:string_tree(),
binary(),
binary(),
oaspec@openapi@spec:operation(),
binary(),
oaspec@codegen@context:context()
) -> gleam@string_tree:string_tree().
generate_request_construction(Sb, Request_type_name, Op_id, Operation, Path, _) ->
Path_segments = begin
_pipe = Path,
_pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>),
gleam@list:filter(_pipe@1, fun(S) -> S /= <<""/utf8>> end)
end,
Path_param_indices = begin
_pipe@2 = gleam@list:index_map(
Path_segments,
fun(Seg, Idx) -> {Seg, Idx} end
),
_pipe@3 = gleam@list:filter(
_pipe@2,
fun(Entry) ->
{Seg@1, _} = Entry,
is_path_param(Seg@1)
end
),
gleam@list:map(
_pipe@3,
fun(Entry@1) ->
{Seg@2, Idx@1} = Entry@1,
Name = extract_param_name(Seg@2),
{Name, Idx@1}
end
)
end,
Sb@2 = gleam@list:fold(
Path_param_indices,
Sb,
fun(Sb@1, Entry@2) ->
{Name@1, _} = Entry@2,
Var_name = <<(oaspec@util@naming:to_snake_case(Name@1))/binary,
"_param"/utf8>>,
_ = Var_name,
Sb@1
end
),
Sb@3 = begin
_pipe@4 = Sb@2,
oaspec@util@string_extra:indent(
_pipe@4,
3,
<<<<"let request = request_types."/utf8, Request_type_name/binary>>/binary,
"("/utf8>>
)
end,
Params = erlang:element(6, Operation),
Sb@5 = gleam@list:index_fold(
Params,
Sb@3,
fun(Sb@4, Param, _) ->
Field_name = oaspec@util@naming:to_snake_case(
erlang:element(2, Param)
),
Trailing = <<","/utf8>>,
Value_expr = case erlang:element(3, Param) of
in_path ->
Var_name@1 = oaspec@util@naming:to_snake_case(
erlang:element(2, Param)
),
param_parse_expr(Var_name@1, Param);
in_query ->
Key = erlang:element(2, Param),
case erlang:element(5, Param) of
true ->
query_required_expr(Key, Param);
false ->
query_optional_expr(Key, Param)
end;
in_header ->
Key@1 = erlang:element(2, Param),
case erlang:element(5, Param) of
true ->
header_required_expr(Key@1, Param);
false ->
header_optional_expr(Key@1, Param)
end;
in_cookie ->
case erlang:element(5, Param) of
true ->
<<"\"\" // TODO: Extract cookie param "/utf8,
(erlang:element(2, Param))/binary>>;
false ->
<<"None // TODO: Extract cookie param "/utf8,
(erlang:element(2, Param))/binary>>
end
end,
_pipe@5 = Sb@4,
oaspec@util@string_extra:indent(
_pipe@5,
4,
<<<<<<Field_name/binary, ": "/utf8>>/binary, Value_expr/binary>>/binary,
Trailing/binary>>
)
end
),
Sb@6 = case erlang:element(7, Operation) of
{some, Rb} ->
Body_expr = generate_body_decode_expr(Rb, Op_id),
_pipe@6 = Sb@5,
oaspec@util@string_extra:indent(
_pipe@6,
4,
<<<<"body: "/utf8, Body_expr/binary>>/binary, ","/utf8>>
);
none ->
Sb@5
end,
_pipe@7 = Sb@6,
oaspec@util@string_extra:indent(_pipe@7, 3, <<")"/utf8>>).
-file("src/oaspec/codegen/server.gleam", 329).
?DOC(" Generate the body of a single route case branch.\n").
-spec generate_route_body(
gleam@string_tree:string_tree(),
binary(),
binary(),
oaspec@openapi@spec:operation(),
binary(),
boolean(),
oaspec@codegen@context:context()
) -> gleam@string_tree:string_tree().
generate_route_body(Sb, Op_id, Fn_name, Operation, Path, Has_params, Ctx) ->
Type_name = oaspec@util@naming:schema_to_type_name(Op_id),
Response_type_name = <<Type_name/binary, "Response"/utf8>>,
case Has_params of
false ->
_pipe = Sb,
_pipe@1 = oaspec@util@string_extra:indent(
_pipe,
3,
<<<<"let response = handlers."/utf8, Fn_name/binary>>/binary,
"()"/utf8>>
),
generate_response_conversion(
_pipe@1,
Response_type_name,
Operation,
Ctx
);
true ->
Request_type_name = <<Type_name/binary, "Request"/utf8>>,
Sb@1 = generate_request_construction(
Sb,
Request_type_name,
Op_id,
Operation,
Path,
Ctx
),
_pipe@2 = Sb@1,
_pipe@3 = oaspec@util@string_extra:indent(
_pipe@2,
3,
<<<<"let response = handlers."/utf8, Fn_name/binary>>/binary,
"(request)"/utf8>>
),
generate_response_conversion(
_pipe@3,
Response_type_name,
Operation,
Ctx
)
end.
-file("src/oaspec/codegen/server.gleam", 732).
?DOC(" Convert an OpenAPI path to a Gleam pattern match expression.\n").
-spec path_to_pattern(binary()) -> binary().
path_to_pattern(Path) ->
Segments = begin
_pipe = Path,
_pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>),
gleam@list:filter(_pipe@1, fun(S) -> S /= <<""/utf8>> end)
end,
Patterns = gleam@list:map(Segments, fun(Seg) -> case is_path_param(Seg) of
true ->
Param_name = extract_param_name(Seg),
oaspec@util@naming:to_snake_case(Param_name);
false ->
<<<<"\""/utf8, Seg/binary>>/binary, "\""/utf8>>
end end),
<<<<"["/utf8,
(oaspec@util@string_extra:join_with(Patterns, <<", "/utf8>>))/binary>>/binary,
"]"/utf8>>.
-file("src/oaspec/codegen/server.gleam", 162).
?DOC(" Generate a router module that dispatches requests.\n").
-spec generate_router(oaspec@codegen@context:context()) -> binary().
generate_router(Ctx) ->
Operations = oaspec@codegen@types:collect_operations(Ctx),
Needs_dict = gleam@list:any(
Operations,
fun(Op) ->
{_, Operation, _, _} = Op,
Has_query = gleam@list:any(
erlang:element(6, Operation),
fun(P) -> erlang:element(3, P) =:= in_query end
),
Has_header = gleam@list:any(
erlang:element(6, Operation),
fun(P@1) -> erlang:element(3, P@1) =:= in_header end
),
Has_query orelse Has_header
end
),
Needs_int = gleam@list:any(
Operations,
fun(Op@1) ->
{_, Operation@1, _, _} = Op@1,
gleam@list:any(
erlang:element(6, Operation@1),
fun(P@2) -> case erlang:element(6, P@2) of
{some, {inline, {integer_schema, _, _, _, _, _, _, _}}} ->
true;
_ ->
false
end end
)
end
),
Needs_option = gleam@list:any(
Operations,
fun(Op@2) ->
{_, Operation@2, _, _} = Op@2,
Has_optional_params = gleam@list:any(
erlang:element(6, Operation@2),
fun(P@3) -> not erlang:element(5, P@3) end
),
Has_optional_body = case erlang:element(7, Operation@2) of
{some, Rb} ->
not erlang:element(4, Rb);
none ->
false
end,
Has_optional_params orelse Has_optional_body
end
),
Needs_json = gleam@list:any(
Operations,
fun(Op@3) ->
{_, Operation@3, _, _} = Op@3,
Responses = maps:to_list(erlang:element(8, Operation@3)),
gleam@list:any(
Responses,
fun(Entry) ->
{_, Response} = Entry,
Content_entries = maps:to_list(erlang:element(3, Response)),
case Content_entries of
[{Media_type_name, Media_type}] ->
case Media_type_name of
<<"application/json"/utf8>> ->
case erlang:element(2, Media_type) of
{some, _} ->
true;
none ->
false
end;
_ ->
false
end;
_ ->
false
end
end
)
end
),
Needs_decode = Needs_json andalso gleam@list:any(
Operations,
fun(Op@4) ->
{_, Operation@4, _, _} = Op@4,
gleam@option:is_some(erlang:element(7, Operation@4))
end
),
Needs_encode = Needs_json,
Has_params_ops = gleam@list:any(
Operations,
fun(Op@5) ->
{_, Operation@5, _, _} = Op@5,
not gleam@list:is_empty(erlang:element(6, Operation@5)) orelse gleam@option:is_some(
erlang:element(7, Operation@5)
)
end
),
_ = Needs_dict,
Std_imports = [<<"gleam/dict.{type Dict}"/utf8>>],
Std_imports@1 = case Needs_int of
true ->
lists:append(Std_imports, [<<"gleam/int"/utf8>>]);
false ->
Std_imports
end,
Std_imports@2 = case Needs_option of
true ->
lists:append(Std_imports@1, [<<"gleam/option.{None, Some}"/utf8>>]);
false ->
Std_imports@1
end,
Std_imports@3 = case Needs_json of
true ->
lists:append(Std_imports@2, [<<"gleam/json"/utf8>>]);
false ->
Std_imports@2
end,
Pkg_imports = [<<(erlang:element(5, erlang:element(3, Ctx)))/binary,
"/handlers"/utf8>>],
Pkg_imports@1 = case Needs_decode of
true ->
lists:append(
Pkg_imports,
[<<(erlang:element(5, erlang:element(3, Ctx)))/binary,
"/decode"/utf8>>]
);
false ->
Pkg_imports
end,
Pkg_imports@2 = case Needs_encode of
true ->
lists:append(
Pkg_imports@1,
[<<(erlang:element(5, erlang:element(3, Ctx)))/binary,
"/encode"/utf8>>]
);
false ->
Pkg_imports@1
end,
Pkg_imports@3 = case Has_params_ops of
true ->
lists:append(
Pkg_imports@2,
[<<(erlang:element(5, erlang:element(3, Ctx)))/binary,
"/request_types"/utf8>>,
<<(erlang:element(5, erlang:element(3, Ctx)))/binary,
"/response_types"/utf8>>]
);
false ->
lists:append(
Pkg_imports@2,
[<<(erlang:element(5, erlang:element(3, Ctx)))/binary,
"/response_types"/utf8>>]
)
end,
All_imports = lists:append(Std_imports@3, Pkg_imports@3),
Sb = begin
_pipe = oaspec@util@string_extra:file_header(<<"0.5.0"/utf8>>),
oaspec@util@string_extra:imports(_pipe, All_imports)
end,
Sb@1 = begin
_pipe@1 = Sb,
_pipe@2 = oaspec@util@string_extra:doc_comment(
_pipe@1,
<<"A server response with status code, body, and headers."/utf8>>
),
_pipe@3 = oaspec@util@string_extra:line(
_pipe@2,
<<"pub type ServerResponse {"/utf8>>
),
_pipe@4 = oaspec@util@string_extra:indent(
_pipe@3,
1,
<<"ServerResponse(status: Int, body: String, headers: List(#(String, String)))"/utf8>>
),
_pipe@5 = oaspec@util@string_extra:line(_pipe@4, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@5)
end,
Sb@2 = begin
_pipe@6 = Sb@1,
_pipe@7 = oaspec@util@string_extra:doc_comment(
_pipe@6,
<<"Route an incoming request to the appropriate handler."/utf8>>
),
_pipe@8 = oaspec@util@string_extra:line(
_pipe@7,
<<"pub fn route(method: String, path: List(String), query: Dict(String, String), headers: Dict(String, String), body: String) -> ServerResponse {"/utf8>>
),
oaspec@util@string_extra:indent(
_pipe@8,
1,
<<"case method, path {"/utf8>>
)
end,
Sb@4 = gleam@list:fold(
Operations,
Sb@2,
fun(Sb@3, Op@6) ->
{Op_id, Operation@6, Path, Method} = Op@6,
Fn_name = oaspec@util@naming:operation_to_function_name(Op_id),
Method_str = oaspec@openapi@spec:method_to_string(Method),
Path_pattern = path_to_pattern(Path),
Has_params = not gleam@list:is_empty(erlang:element(6, Operation@6))
orelse gleam@option:is_some(erlang:element(7, Operation@6)),
_pipe@9 = Sb@3,
_pipe@10 = oaspec@util@string_extra:indent(
_pipe@9,
2,
<<<<<<<<"\""/utf8, Method_str/binary>>/binary, "\", "/utf8>>/binary,
Path_pattern/binary>>/binary,
" -> {"/utf8>>
),
_pipe@11 = generate_route_body(
_pipe@10,
Op_id,
Fn_name,
Operation@6,
Path,
Has_params,
Ctx
),
oaspec@util@string_extra:indent(_pipe@11, 2, <<"}"/utf8>>)
end
),
Sb@5 = begin
_pipe@12 = Sb@4,
_pipe@13 = oaspec@util@string_extra:indent(
_pipe@12,
2,
<<"_, _ -> ServerResponse(status: 404, body: \"Not Found\", headers: [])"/utf8>>
),
_pipe@14 = oaspec@util@string_extra:indent(_pipe@13, 1, <<"}"/utf8>>),
_pipe@15 = oaspec@util@string_extra:line(_pipe@14, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@15)
end,
oaspec@util@string_extra:to_string(Sb@5).
-file("src/oaspec/codegen/server.gleam", 14).
?DOC(" Generate server stub files.\n").
-spec generate(oaspec@codegen@context:context()) -> list(oaspec@codegen@context:generated_file()).
generate(Ctx) ->
Handlers_content = generate_handlers(Ctx),
Router_content = generate_router(Ctx),
[{generated_file,
<<"handlers.gleam"/utf8>>,
Handlers_content,
server_target},
{generated_file, <<"router.gleam"/utf8>>, Router_content, server_target}].