Packages
oaspec
0.5.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.0
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.1
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.3
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.1.3
Generate Gleam code from OpenAPI 3.x specifications
Current section
Files
Jump to
Current section
Files
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}].