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", 66).
?DOC(" Generate a single handler stub.\n").
-spec generate_handler(
gleam@string_tree:string_tree(),
binary(),
oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved()),
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,
<<<<"panic as \"unimplemented: "/utf8, Fn_name/binary>>/binary,
"\""/utf8>>
),
_pipe@7 = oaspec@util@string_extra:line(_pipe@6, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@7).
-file("src/oaspec/codegen/server.gleam", 40).
?DOC(" Generate handler stubs for all operations.\n").
-spec generate_handlers(
oaspec@codegen@context:context(),
list({binary(),
oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved()),
binary(),
oaspec@openapi@spec:http_method()})
) -> binary().
generate_handlers(Ctx, Operations) ->
Sb = begin
_pipe = oaspec@util@string_extra:file_header(<<"0.16.0"/utf8>>),
oaspec@util@string_extra:imports(
_pipe,
[<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/request_types"/utf8>>,
<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/response_types"/utf8>>]
)
end,
Sb@2 = gleam@list:fold(
Operations,
Sb,
fun(Sb@1, Op) ->
{Op_id, Operation, _, _} = Op,
generate_handler(Sb@1, Op_id, Operation, Ctx)
end
),
oaspec@util@string_extra:to_string(Sb@2).
-file("src/oaspec/codegen/server.gleam", 813).
-spec route_arg_name(binary(), boolean()) -> binary().
route_arg_name(Name, Used) ->
gleam@bool:guard(Used, Name, fun() -> <<"_"/utf8, Name/binary>> end).
-file("src/oaspec/codegen/server.gleam", 818).
-spec generate_cookie_lookup(gleam@string_tree:string_tree()) -> gleam@string_tree:string_tree().
generate_cookie_lookup(Sb) ->
_pipe = Sb,
_pipe@1 = oaspec@util@string_extra:doc_comment(
_pipe,
<<"Extract a cookie value from the Cookie header."/utf8>>
),
_pipe@2 = oaspec@util@string_extra:line(
_pipe@1,
<<"fn cookie_lookup(headers: Dict(String, String), key: String) -> Result(String, Nil) {"/utf8>>
),
_pipe@3 = oaspec@util@string_extra:indent(
_pipe@2,
1,
<<"case dict.get(headers, \"cookie\") {"/utf8>>
),
_pipe@4 = oaspec@util@string_extra:indent(_pipe@3, 2, <<"Ok(raw) ->"/utf8>>),
_pipe@5 = oaspec@util@string_extra:indent(
_pipe@4,
3,
<<"list.find_map(string.split(raw, \";\"), fn(part) {"/utf8>>
),
_pipe@6 = oaspec@util@string_extra:indent(
_pipe@5,
4,
<<"let trimmed = string.trim(part)"/utf8>>
),
_pipe@7 = oaspec@util@string_extra:indent(
_pipe@6,
4,
<<"case string.split_once(trimmed, on: \"=\") {"/utf8>>
),
_pipe@8 = oaspec@util@string_extra:indent(
_pipe@7,
5,
<<"Ok(#(cookie_key, cookie_value)) ->"/utf8>>
),
_pipe@9 = oaspec@util@string_extra:indent(
_pipe@8,
6,
<<"case string.trim(cookie_key) == key {"/utf8>>
),
_pipe@10 = oaspec@util@string_extra:indent(
_pipe@9,
7,
<<"True -> uri.percent_decode(string.trim(cookie_value))"/utf8>>
),
_pipe@11 = oaspec@util@string_extra:indent(
_pipe@10,
7,
<<"False -> Error(Nil)"/utf8>>
),
_pipe@12 = oaspec@util@string_extra:indent(_pipe@11, 6, <<"}"/utf8>>),
_pipe@13 = oaspec@util@string_extra:indent(
_pipe@12,
5,
<<"Error(_) -> Error(Nil)"/utf8>>
),
_pipe@14 = oaspec@util@string_extra:indent(_pipe@13, 4, <<"}"/utf8>>),
_pipe@15 = oaspec@util@string_extra:indent(_pipe@14, 3, <<"})"/utf8>>),
_pipe@16 = oaspec@util@string_extra:indent(
_pipe@15,
2,
<<"Error(_) -> Error(Nil)"/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).
-file("src/oaspec/codegen/server.gleam", 1128).
?DOC(
" Check if an operation's request body needs guard validation.\n"
" True when the body is required, JSON-compatible, references a named schema,\n"
" and that schema has constraint-based validators.\n"
).
-spec operation_needs_guard_validation(
oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved()),
oaspec@codegen@context:context()
) -> boolean().
operation_needs_guard_validation(Operation, Ctx) ->
case erlang:element(7, Operation) of
{some, {value, Rb}} ->
erlang:element(4, Rb) andalso begin
Content_entries = maps:to_list(erlang:element(3, Rb)),
gleam@list:any(
Content_entries,
fun(Entry) ->
oaspec@util@content_type:is_json_compatible(
erlang:element(1, Entry)
)
end
)
andalso case Content_entries of
[{_, Mt}] ->
case erlang:element(2, Mt) of
{some, {reference, _, Name}} ->
oaspec@codegen@guards:schema_has_validator(
Name,
Ctx
);
_ ->
false
end;
_ ->
false
end
end;
_ ->
false
end.
-file("src/oaspec/codegen/server.gleam", 1312).
?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", 1158).
?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@openapi@spec:resolved()),
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, Ref_or} = Entry,
case Ref_or of
{value, Response} ->
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 oaspec@util@content_type:from_string(
Media_type_name
) of
application_json ->
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\", \""/utf8>>/binary,
Media_type_name/binary>>/binary,
"\")])"/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 ->
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 ->
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 ->
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 ->
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;
[{First_media_type, _}, _ | _] ->
_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: [#(\"content-type\", \""/utf8>>/binary,
First_media_type/binary>>/binary,
"\")])"/utf8>>
)
end;
_ ->
Sb@2
end
end
),
_pipe@10 = Sb@3,
oaspec@util@string_extra:indent(_pipe@10, 3, <<"}"/utf8>>)
end.
-file("src/oaspec/codegen/server.gleam", 884).
?DOC(
" Generate safe request construction wrapped in error handling.\n"
" Path parameter parsing, required query/header/cookie params, and body\n"
" decoding are all validated before calling the handler. Parse failures\n"
" return ServerResponse(status: 400) instead of crashing.\n"
).
-spec generate_safe_request_and_dispatch(
gleam@string_tree:string_tree(),
binary(),
binary(),
binary(),
binary(),
oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved()),
binary(),
oaspec@codegen@context:context()
) -> gleam@string_tree:string_tree().
generate_safe_request_and_dispatch(
Sb,
Request_type_name,
Response_type_name,
Op_id,
Fn_name,
Operation,
_,
Ctx
) ->
Params = gleam@list:filter_map(
erlang:element(6, Operation),
fun(R) -> case R of
{value, P} ->
{ok, P};
_ ->
{error, nil}
end end
),
Path_params_needing_parse = gleam@list:filter(
Params,
fun(P@1) ->
(erlang:element(3, P@1) =:= in_path) andalso oaspec@codegen@server_request_decode:param_needs_result_unwrap(
P@1
)
end
),
Needs_body_guard = case erlang:element(7, Operation) of
{some, {value, Rb}} ->
erlang:element(4, Rb) andalso gleam@list:any(
maps:to_list(erlang:element(3, Rb)),
fun(Entry) ->
oaspec@util@content_type:is_json_compatible(
erlang:element(1, Entry)
)
end
);
_ ->
false
end,
Sb@2 = gleam@list:fold(
Path_params_needing_parse,
Sb,
fun(Sb@1, P@2) ->
Var_name = oaspec@util@naming:to_snake_case(erlang:element(2, P@2)),
Parse_expr = oaspec@codegen@server_request_decode:param_parse_expr(
Var_name,
P@2
),
_pipe = Sb@1,
_pipe@1 = oaspec@util@string_extra:indent(
_pipe,
3,
<<<<"case "/utf8, Parse_expr/binary>>/binary, " {"/utf8>>
),
oaspec@util@string_extra:indent(
_pipe@1,
4,
<<<<"Ok("/utf8, Var_name/binary>>/binary, "_parsed) -> {"/utf8>>
)
end
),
Body_schema_ref_name = case erlang:element(7, Operation) of
{some, {value, Rb@1}} ->
Content_entries = maps:to_list(erlang:element(3, Rb@1)),
case Content_entries of
[{_, Media_type}] ->
case erlang:element(2, Media_type) of
{some, {reference, _, Name}} ->
{some, Name};
_ ->
none
end;
_ ->
none
end;
_ ->
none
end,
Needs_guard_validation = (oaspec@config:validate(
oaspec@codegen@context:config(Ctx)
)
andalso Needs_body_guard)
andalso (case Body_schema_ref_name of
{some, Name@1} ->
oaspec@codegen@guards:schema_has_validator(Name@1, Ctx);
none ->
false
end),
Sb@3 = case {Needs_body_guard, erlang:element(7, Operation)} of
{true, {some, {value, Rb@2}}} ->
Content_entries@1 = maps:to_list(erlang:element(3, Rb@2)),
case Content_entries@1 of
[{_, Media_type@1}] ->
case erlang:element(2, Media_type@1) of
{some, {reference, _, Name@2}} ->
Decode_fn = <<<<"decode.decode_"/utf8,
(oaspec@util@naming:to_snake_case(Name@2))/binary>>/binary,
"(body)"/utf8>>,
_pipe@2 = Sb@2,
_pipe@3 = oaspec@util@string_extra:indent(
_pipe@2,
3,
<<<<"case "/utf8, Decode_fn/binary>>/binary,
" {"/utf8>>
),
oaspec@util@string_extra:indent(
_pipe@3,
4,
<<"Ok(decoded_body) -> {"/utf8>>
);
_ ->
Decode_fn@1 = <<<<"decode.decode_"/utf8,
(oaspec@util@naming:to_snake_case(Op_id))/binary>>/binary,
"_request_body(body)"/utf8>>,
_pipe@4 = Sb@2,
_pipe@5 = oaspec@util@string_extra:indent(
_pipe@4,
3,
<<<<"case "/utf8, Decode_fn@1/binary>>/binary,
" {"/utf8>>
),
oaspec@util@string_extra:indent(
_pipe@5,
4,
<<"Ok(decoded_body) -> {"/utf8>>
)
end;
_ ->
Sb@2
end;
{_, _} ->
Sb@2
end,
Sb@4 = case {Needs_guard_validation, Body_schema_ref_name} of
{true, {some, Name@3}} ->
Validate_fn = <<<<"guards.validate_"/utf8,
(oaspec@util@naming:to_snake_case(Name@3))/binary>>/binary,
"(decoded_body)"/utf8>>,
_pipe@6 = Sb@3,
_pipe@7 = oaspec@util@string_extra:indent(
_pipe@6,
3,
<<<<"case "/utf8, Validate_fn/binary>>/binary, " {"/utf8>>
),
oaspec@util@string_extra:indent(
_pipe@7,
4,
<<"Ok(decoded_body) -> {"/utf8>>
);
{_, _} ->
Sb@3
end,
Sb@5 = case erlang:element(7, Operation) of
{some, {value, Rb@3}} ->
case oaspec@codegen@server_request_decode:request_body_uses_form_urlencoded(
Rb@3
) of
true ->
_pipe@8 = Sb@4,
oaspec@util@string_extra:indent(
_pipe@8,
3,
<<"let form_body = parse_form_body(body)"/utf8>>
);
false ->
case oaspec@codegen@server_request_decode:request_body_uses_multipart(
Rb@3
) of
true ->
_pipe@9 = Sb@4,
oaspec@util@string_extra:indent(
_pipe@9,
3,
<<"let multipart_body = parse_multipart_body(body, headers)"/utf8>>
);
false ->
Sb@4
end
end;
_ ->
Sb@4
end,
Sb@6 = begin
_pipe@10 = Sb@5,
oaspec@util@string_extra:indent(
_pipe@10,
3,
<<<<"let request = request_types."/utf8, Request_type_name/binary>>/binary,
"("/utf8>>
)
end,
Sb@8 = gleam@list:fold(
Params,
Sb@6,
fun(Sb@7, 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 ->
case oaspec@codegen@server_request_decode:param_needs_result_unwrap(
Param
) of
true ->
<<(oaspec@util@naming:to_snake_case(
erlang:element(2, Param)
))/binary,
"_parsed"/utf8>>;
false ->
Var_name@1 = oaspec@util@naming:to_snake_case(
erlang:element(2, Param)
),
oaspec@codegen@server_request_decode:param_parse_expr(
Var_name@1,
Param
)
end;
in_query ->
Key = erlang:element(2, Param),
case {oaspec@codegen@server_request_decode:is_deep_object_param(
Param,
Ctx
),
erlang:element(5, Param)} of
{true, true} ->
oaspec@codegen@server_request_decode:deep_object_required_expr(
Key,
Param,
Op_id,
Ctx
);
{true, false} ->
oaspec@codegen@server_request_decode:deep_object_optional_expr(
Key,
Param,
Op_id,
Ctx
);
{false, true} ->
oaspec@codegen@server_request_decode:query_required_expr(
Key,
Param
);
{false, false} ->
oaspec@codegen@server_request_decode:query_optional_expr(
Key,
Param
)
end;
in_header ->
Key@1 = string:lowercase(erlang:element(2, Param)),
case erlang:element(5, Param) of
true ->
oaspec@codegen@server_request_decode:header_required_expr(
Key@1,
Param
);
false ->
oaspec@codegen@server_request_decode:header_optional_expr(
Key@1,
Param
)
end;
in_cookie ->
Key@2 = erlang:element(2, Param),
case erlang:element(5, Param) of
true ->
oaspec@codegen@server_request_decode:cookie_required_expr(
Key@2,
Param
);
false ->
oaspec@codegen@server_request_decode:cookie_optional_expr(
Key@2,
Param
)
end
end,
_pipe@11 = Sb@7,
oaspec@util@string_extra:indent(
_pipe@11,
4,
<<<<<<Field_name/binary, ": "/utf8>>/binary, Value_expr/binary>>/binary,
Trailing/binary>>
)
end
),
Sb@9 = case Needs_body_guard of
true ->
_pipe@12 = Sb@8,
oaspec@util@string_extra:indent(
_pipe@12,
4,
<<"body: decoded_body,"/utf8>>
);
false ->
case erlang:element(7, Operation) of
{some, {value, Rb@4}} ->
Body_expr = oaspec@codegen@server_request_decode:generate_body_decode_expr(
Rb@4,
Op_id,
Ctx
),
_pipe@13 = Sb@8,
oaspec@util@string_extra:indent(
_pipe@13,
4,
<<<<"body: "/utf8, Body_expr/binary>>/binary, ","/utf8>>
);
_ ->
Sb@8
end
end,
Sb@10 = begin
_pipe@14 = Sb@9,
oaspec@util@string_extra:indent(_pipe@14, 3, <<")"/utf8>>)
end,
Sb@11 = begin
_pipe@15 = Sb@10,
_pipe@16 = oaspec@util@string_extra:indent(
_pipe@15,
3,
<<<<"let response = handlers."/utf8, Fn_name/binary>>/binary,
"(request)"/utf8>>
),
generate_response_conversion(
_pipe@16,
Response_type_name,
Operation,
Ctx
)
end,
Sb@12 = case Needs_guard_validation of
true ->
_pipe@17 = Sb@11,
_pipe@18 = oaspec@util@string_extra:indent(
_pipe@17,
4,
<<"}"/utf8>>
),
_pipe@19 = oaspec@util@string_extra:indent(
_pipe@18,
4,
<<"Error(errors) -> ServerResponse(status: 422, body: json.to_string(json.array(errors, json.string)), headers: [#(\"content-type\", \"application/json\")])"/utf8>>
),
oaspec@util@string_extra:indent(_pipe@19, 3, <<"}"/utf8>>);
false ->
Sb@11
end,
Sb@13 = case Needs_body_guard of
true ->
_pipe@20 = Sb@12,
_pipe@21 = oaspec@util@string_extra:indent(
_pipe@20,
4,
<<"}"/utf8>>
),
_pipe@22 = oaspec@util@string_extra:indent(
_pipe@21,
4,
<<"Error(_) -> ServerResponse(status: 400, body: \"Bad Request\", headers: [])"/utf8>>
),
oaspec@util@string_extra:indent(_pipe@22, 3, <<"}"/utf8>>);
false ->
Sb@12
end,
gleam@list:fold(
Path_params_needing_parse,
Sb@13,
fun(Sb@14, _) -> _pipe@23 = Sb@14,
_pipe@24 = oaspec@util@string_extra:indent(
_pipe@23,
4,
<<"}"/utf8>>
),
_pipe@25 = oaspec@util@string_extra:indent(
_pipe@24,
4,
<<"Error(_) -> ServerResponse(status: 400, body: \"Bad Request\", headers: [])"/utf8>>
),
oaspec@util@string_extra:indent(_pipe@25, 3, <<"}"/utf8>>) end
).
-file("src/oaspec/codegen/server.gleam", 844).
?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(oaspec@openapi@spec:resolved()),
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>>,
generate_safe_request_and_dispatch(
Sb,
Request_type_name,
Response_type_name,
Op_id,
Fn_name,
Operation,
Path,
Ctx
)
end.
-file("src/oaspec/codegen/server.gleam", 1359).
?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", 1367).
?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", 1338).
?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", 120).
?DOC(" Generate a router module that dispatches requests.\n").
-spec generate_router(
oaspec@codegen@context:context(),
list({binary(),
oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved()),
binary(),
oaspec@openapi@spec:http_method()})
) -> binary().
generate_router(Ctx, Operations) ->
Has_deep_object = gleam@list:any(
Operations,
fun(Op) ->
{_, Operation, _, _} = Op,
gleam@list:any(
erlang:element(6, Operation),
fun(Ref_p) -> case Ref_p of
{value, P} ->
oaspec@codegen@server_request_decode:is_deep_object_param(
P,
Ctx
);
_ ->
false
end end
)
end
),
Has_deep_object_with_ap = gleam@list:any(
Operations,
fun(Op@1) ->
{_, Operation@1, _, _} = Op@1,
gleam@list:any(
erlang:element(6, Operation@1),
fun(Ref_p@1) -> case Ref_p@1 of
{value, P@1} ->
oaspec@codegen@server_request_decode:is_deep_object_param(
P@1,
Ctx
)
andalso oaspec@codegen@server_request_decode:deep_object_has_additional_properties(
P@1,
Ctx
);
_ ->
false
end end
)
end
),
Needs_deep_object_present = gleam@list:any(
Operations,
fun(Op@2) ->
{_, Operation@2, _, _} = Op@2,
gleam@list:any(
erlang:element(6, Operation@2),
fun(Ref_p@2) -> case Ref_p@2 of
{value, P@2} ->
(oaspec@codegen@server_request_decode:is_deep_object_param(
P@2,
Ctx
)
andalso not erlang:element(5, P@2))
andalso not oaspec@codegen@server_request_decode:deep_object_has_untyped_additional_properties(
P@2,
Ctx
);
_ ->
false
end end
)
end
),
Has_deep_object_untyped_ap = gleam@list:any(
Operations,
fun(Op@3) ->
{_, Operation@3, _, _} = Op@3,
gleam@list:any(
erlang:element(6, Operation@3),
fun(Ref_p@3) -> case Ref_p@3 of
{value, P@3} ->
oaspec@codegen@server_request_decode:is_deep_object_param(
P@3,
Ctx
)
andalso oaspec@codegen@server_request_decode:deep_object_has_untyped_additional_properties(
P@3,
Ctx
);
_ ->
false
end end
)
end
),
Has_form_urlencoded_body = gleam@list:any(
Operations,
fun(Op@4) ->
{_, Operation@4, _, _} = Op@4,
oaspec@codegen@server_request_decode:operation_uses_form_urlencoded_body(
Operation@4
)
end
),
Has_multipart_body = gleam@list:any(
Operations,
fun(Op@5) ->
{_, Operation@5, _, _} = Op@5,
oaspec@codegen@server_request_decode:operation_uses_multipart_body(
Operation@5
)
end
),
Has_nested_form_urlencoded_body = gleam@list:any(
Operations,
fun(Op@6) ->
{_, Operation@6, _, _} = Op@6,
case erlang:element(7, Operation@6) of
{some, {value, Rb}} ->
oaspec@codegen@server_request_decode:form_urlencoded_body_has_nested_object(
Rb,
Ctx
);
_ ->
false
end
end
),
Needs_int = gleam@list:any(
Operations,
fun(Op@7) ->
{_, Operation@7, _, _} = Op@7,
(gleam@list:any(
erlang:element(6, Operation@7),
fun(Ref_p@4) -> case Ref_p@4 of
{value, P@4} ->
oaspec@codegen@server_request_decode:query_schema_needs_int(
oaspec@openapi@spec:parameter_schema(P@4)
)
orelse oaspec@codegen@server_request_decode:deep_object_param_needs_int(
P@4,
Ctx
);
_ ->
false
end end
)
orelse case erlang:element(7, Operation@7) of
{some, {value, Rb@1}} ->
oaspec@codegen@server_request_decode:form_urlencoded_body_needs_int(
Rb@1,
Ctx
);
_ ->
false
end)
orelse case erlang:element(7, Operation@7) of
{some, {value, Rb@2}} ->
oaspec@codegen@server_request_decode:multipart_body_needs_int(
Rb@2,
Ctx
);
_ ->
false
end
end
),
Needs_float = gleam@list:any(
Operations,
fun(Op@8) ->
{_, Operation@8, _, _} = Op@8,
(gleam@list:any(
erlang:element(6, Operation@8),
fun(Ref_p@5) -> case Ref_p@5 of
{value, P@5} ->
oaspec@codegen@server_request_decode:query_schema_needs_float(
oaspec@openapi@spec:parameter_schema(P@5)
)
orelse oaspec@codegen@server_request_decode:deep_object_param_needs_float(
P@5,
Ctx
);
_ ->
false
end end
)
orelse case erlang:element(7, Operation@8) of
{some, {value, Rb@3}} ->
oaspec@codegen@server_request_decode:form_urlencoded_body_needs_float(
Rb@3,
Ctx
);
_ ->
false
end)
orelse case erlang:element(7, Operation@8) of
{some, {value, Rb@4}} ->
oaspec@codegen@server_request_decode:multipart_body_needs_float(
Rb@4,
Ctx
);
_ ->
false
end
end
),
Needs_string = ((Has_form_urlencoded_body orelse Has_multipart_body) orelse Has_deep_object_with_ap)
orelse gleam@list:any(
Operations,
fun(Op@9) ->
{_, Operation@9, _, _} = Op@9,
gleam@list:any(
erlang:element(6, Operation@9),
fun(Ref_p@6) -> case Ref_p@6 of
{value, P@6} ->
case erlang:element(3, P@6) of
in_cookie ->
true;
in_query ->
oaspec@codegen@server_request_decode:query_schema_needs_string(
oaspec@openapi@spec:parameter_schema(
P@6
)
)
orelse oaspec@codegen@server_request_decode:deep_object_param_needs_string(
P@6,
Ctx
);
in_header ->
oaspec@codegen@server_request_decode:query_schema_needs_string(
oaspec@openapi@spec:parameter_schema(
P@6
)
)
orelse oaspec@codegen@server_request_decode:deep_object_param_needs_string(
P@6,
Ctx
);
in_path ->
oaspec@codegen@server_request_decode:query_schema_needs_string(
oaspec@openapi@spec:parameter_schema(
P@6
)
)
end;
_ ->
false
end end
)
orelse case erlang:element(7, Operation@9) of
{some, {value, Rb@5}} ->
oaspec@codegen@server_request_decode:form_urlencoded_body_needs_string(
Rb@5,
Ctx
);
_ ->
false
end
end
),
Needs_cookie_lookup = gleam@list:any(
Operations,
fun(Op@10) ->
{_, Operation@10, _, _} = Op@10,
gleam@list:any(
erlang:element(6, Operation@10),
fun(Ref_p@7) -> case Ref_p@7 of
{value, P@7} ->
erlang:element(3, P@7) =:= in_cookie;
_ ->
false
end end
)
end
),
Needs_list_import = (((Needs_cookie_lookup orelse Has_deep_object) orelse Has_form_urlencoded_body)
orelse Has_multipart_body)
orelse gleam@list:any(
Operations,
fun(Op@11) ->
{_, Operation@11, _, _} = Op@11,
gleam@list:any(
erlang:element(6, Operation@11),
fun(Ref_p@8) -> case Ref_p@8 of
{value, P@8} ->
case {erlang:element(3, P@8),
oaspec@openapi@spec:parameter_schema(P@8)} of
{in_query,
{some,
{inline, {array_schema, _, _, _, _, _}}}} ->
true;
{in_header,
{some,
{inline, {array_schema, _, _, _, _, _}}}} ->
true;
{_, _} ->
false
end;
_ ->
false
end end
)
end
),
Needs_uri_import = Needs_cookie_lookup orelse Has_form_urlencoded_body,
Needs_option = (oaspec@codegen@import_analysis:operations_have_optional_params(
Operations
)
orelse oaspec@codegen@import_analysis:operations_have_optional_body(
Operations
))
orelse gleam@list:any(
Operations,
fun(Op@12) ->
{_, Operation@12, _, _} = Op@12,
Has_optional_deep_object_fields = gleam@list:any(
erlang:element(6, Operation@12),
fun(Ref_p@9) -> case Ref_p@9 of
{value, P@9} ->
oaspec@codegen@server_request_decode:deep_object_param_has_optional_fields(
P@9,
Ctx
);
_ ->
false
end end
),
Has_optional_form_urlencoded_fields = case erlang:element(
7,
Operation@12
) of
{some, {value, Rb@6}} ->
oaspec@codegen@server_request_decode:form_urlencoded_body_has_optional_fields(
Rb@6,
Ctx
);
_ ->
false
end,
Has_optional_multipart_fields = case erlang:element(7, Operation@12) of
{some, {value, Rb@7}} ->
oaspec@codegen@server_request_decode:multipart_body_has_optional_fields(
Rb@7,
Ctx
);
_ ->
false
end,
(Has_optional_deep_object_fields orelse Has_optional_form_urlencoded_fields)
orelse Has_optional_multipart_fields
end
),
Needs_json = gleam@list:any(
Operations,
fun(Op@13) ->
{_, Operation@13, _, _} = Op@13,
Responses = maps:to_list(erlang:element(8, Operation@13)),
gleam@list:any(
Responses,
fun(Entry) ->
{_, Ref_or} = Entry,
case Ref_or of
{value, Response} ->
Content_entries = maps:to_list(
erlang:element(3, Response)
),
case Content_entries of
[{Media_type_name, Media_type}] ->
case oaspec@util@content_type:is_json_compatible(
Media_type_name
) of
true ->
case erlang:element(2, Media_type) of
{some, _} ->
true;
none ->
false
end;
false ->
false
end;
_ ->
false
end;
_ ->
false
end
end
)
end
),
Needs_decode = gleam@list:any(
Operations,
fun(Op@14) ->
{_, Operation@14, _, _} = Op@14,
case erlang:element(7, Operation@14) of
{some, {value, Rb@8}} ->
gleam@list:any(
maps:to_list(erlang:element(3, Rb@8)),
fun(Entry@1) ->
{Content_type, _} = Entry@1,
oaspec@util@content_type:is_json_compatible(
Content_type
)
end
);
_ ->
false
end
end
),
Needs_encode = Needs_json,
Uses_query = gleam@list:any(
Operations,
fun(Op@15) ->
{_, Operation@15, _, _} = Op@15,
gleam@list:any(
erlang:element(6, Operation@15),
fun(Ref_p@10) -> case Ref_p@10 of
{value, P@10} ->
erlang:element(3, P@10) =:= in_query;
_ ->
false
end end
)
end
),
Uses_headers = Has_multipart_body orelse gleam@list:any(
Operations,
fun(Op@16) ->
{_, Operation@16, _, _} = Op@16,
gleam@list:any(
erlang:element(6, Operation@16),
fun(Ref_p@11) -> case Ref_p@11 of
{value, P@11} ->
(erlang:element(3, P@11) =:= in_header) orelse (erlang:element(
3,
P@11
)
=:= in_cookie);
_ ->
false
end end
)
end
),
Uses_body = gleam@list:any(
Operations,
fun(Op@17) ->
{_, Operation@17, _, _} = Op@17,
gleam@option:is_some(erlang:element(7, Operation@17))
end
),
Has_params_ops = gleam@list:any(
Operations,
fun(Op@18) ->
{_, Operation@18, _, _} = Op@18,
not gleam@list:is_empty(erlang:element(6, Operation@18)) orelse gleam@option:is_some(
erlang:element(7, Operation@18)
)
end
),
Std_imports = [<<"gleam/dict.{type Dict}"/utf8>>],
Std_imports@1 = case Needs_list_import of
true ->
lists:append(Std_imports, [<<"gleam/list"/utf8>>]);
false ->
Std_imports
end,
Std_imports@2 = case Needs_uri_import of
true ->
lists:append(Std_imports@1, [<<"gleam/uri"/utf8>>]);
false ->
Std_imports@1
end,
Std_imports@3 = case Needs_int of
true ->
lists:append(Std_imports@2, [<<"gleam/int"/utf8>>]);
false ->
Std_imports@2
end,
Std_imports@4 = case Needs_float of
true ->
lists:append(Std_imports@3, [<<"gleam/float"/utf8>>]);
false ->
Std_imports@3
end,
Std_imports@5 = case Needs_option of
true ->
lists:append(Std_imports@4, [<<"gleam/option.{None, Some}"/utf8>>]);
false ->
Std_imports@4
end,
Needs_json_for_guards = oaspec@config:validate(
oaspec@codegen@context:config(Ctx)
)
andalso gleam@list:any(
Operations,
fun(Op@19) ->
{_, Operation@19, _, _} = Op@19,
operation_needs_guard_validation(Operation@19, Ctx)
end
),
Std_imports@6 = case Needs_json orelse Needs_json_for_guards of
true ->
lists:append(Std_imports@5, [<<"gleam/json"/utf8>>]);
false ->
Std_imports@5
end,
Std_imports@7 = case Needs_string of
true ->
lists:append(Std_imports@6, [<<"gleam/string"/utf8>>]);
false ->
Std_imports@6
end,
Std_imports@8 = case Has_deep_object_untyped_ap of
true ->
lists:append(Std_imports@7, [<<"gleam/dynamic"/utf8>>]);
false ->
Std_imports@7
end,
Pkg_imports = [<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/handlers"/utf8>>],
Pkg_imports@1 = case (Has_deep_object orelse Has_form_urlencoded_body)
orelse Has_multipart_body of
true ->
lists:append(
Pkg_imports,
[<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/types"/utf8>>]
);
false ->
Pkg_imports
end,
Pkg_imports@2 = case Needs_decode of
true ->
lists:append(
Pkg_imports@1,
[<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/decode"/utf8>>]
);
false ->
Pkg_imports@1
end,
Pkg_imports@3 = case Needs_encode of
true ->
lists:append(
Pkg_imports@2,
[<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/encode"/utf8>>]
);
false ->
Pkg_imports@2
end,
Pkg_imports@4 = case Has_params_ops of
true ->
lists:append(
Pkg_imports@3,
[<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/request_types"/utf8>>,
<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/response_types"/utf8>>]
);
false ->
lists:append(
Pkg_imports@3,
[<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/response_types"/utf8>>]
)
end,
Needs_guards = oaspec@config:validate(oaspec@codegen@context:config(Ctx))
andalso gleam@list:any(
Operations,
fun(Op@20) ->
{_, Operation@20, _, _} = Op@20,
operation_needs_guard_validation(Operation@20, Ctx)
end
),
Pkg_imports@5 = case Needs_guards of
true ->
lists:append(
Pkg_imports@4,
[<<(oaspec@config:package(oaspec@codegen@context:config(Ctx)))/binary,
"/guards"/utf8>>]
);
false ->
Pkg_imports@4
end,
All_imports = lists:append(Std_imports@8, Pkg_imports@5),
Sb = begin
_pipe = oaspec@util@string_extra:file_header(<<"0.16.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 = case Needs_deep_object_present of
true ->
_pipe@6 = Sb@1,
_pipe@7 = oaspec@util@string_extra:line(
_pipe@6,
<<"fn deep_object_present(query: Dict(String, List(String)), prefix: String, props: List(String)) -> Bool {"/utf8>>
),
_pipe@8 = oaspec@util@string_extra:indent(
_pipe@7,
1,
<<"list.any(props, fn(prop) { dict.has_key(query, prefix <> \"[\" <> prop <> \"]\") })"/utf8>>
),
_pipe@9 = oaspec@util@string_extra:line(_pipe@8, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@9);
false ->
Sb@1
end,
Sb@3 = case Has_deep_object_with_ap of
true ->
_pipe@10 = Sb@2,
_pipe@11 = oaspec@util@string_extra:line(
_pipe@10,
<<"fn deep_object_present_any(query: Dict(String, List(String)), prefix: String) -> Bool {"/utf8>>
),
_pipe@12 = oaspec@util@string_extra:indent(
_pipe@11,
1,
<<"let prefix_bracket = prefix <> \"[\""/utf8>>
),
_pipe@13 = oaspec@util@string_extra:indent(
_pipe@12,
1,
<<"dict.fold(query, False, fn(found, k, _v) { found || string.starts_with(k, prefix_bracket) })"/utf8>>
),
_pipe@14 = oaspec@util@string_extra:line(_pipe@13, <<"}"/utf8>>),
_pipe@15 = oaspec@util@string_extra:blank_line(_pipe@14),
_pipe@16 = oaspec@util@string_extra:line(
_pipe@15,
<<"fn deep_object_additional_properties(query: Dict(String, List(String)), prefix: String, known_props: List(String)) -> Dict(String, List(String)) {"/utf8>>
),
_pipe@17 = oaspec@util@string_extra:indent(
_pipe@16,
1,
<<"let prefix_bracket = prefix <> \"[\""/utf8>>
),
_pipe@18 = oaspec@util@string_extra:indent(
_pipe@17,
1,
<<"let prefix_len = string.length(prefix_bracket)"/utf8>>
),
_pipe@19 = oaspec@util@string_extra:indent(
_pipe@18,
1,
<<"dict.fold(query, dict.new(), fn(acc, k, v) {"/utf8>>
),
_pipe@20 = oaspec@util@string_extra:indent(
_pipe@19,
2,
<<"case string.starts_with(k, prefix_bracket) && string.ends_with(k, \"]\") {"/utf8>>
),
_pipe@21 = oaspec@util@string_extra:indent(
_pipe@20,
3,
<<"True -> {"/utf8>>
),
_pipe@22 = oaspec@util@string_extra:indent(
_pipe@21,
4,
<<"let prop = string.slice(k, prefix_len, string.length(k) - prefix_len - 1)"/utf8>>
),
_pipe@23 = oaspec@util@string_extra:indent(
_pipe@22,
4,
<<"case list.contains(known_props, prop) { True -> acc False -> dict.insert(acc, prop, v) }"/utf8>>
),
_pipe@24 = oaspec@util@string_extra:indent(
_pipe@23,
3,
<<"}"/utf8>>
),
_pipe@25 = oaspec@util@string_extra:indent(
_pipe@24,
3,
<<"False -> acc"/utf8>>
),
_pipe@26 = oaspec@util@string_extra:indent(
_pipe@25,
2,
<<"}"/utf8>>
),
_pipe@27 = oaspec@util@string_extra:indent(
_pipe@26,
1,
<<"})"/utf8>>
),
_pipe@28 = oaspec@util@string_extra:line(_pipe@27, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@28);
false ->
Sb@2
end,
Sb@4 = case Has_deep_object_untyped_ap of
true ->
_pipe@29 = Sb@3,
_pipe@30 = oaspec@util@string_extra:line(
_pipe@29,
<<"@external(erlang, \"gleam_stdlib\", \"identity\")"/utf8>>
),
_pipe@31 = oaspec@util@string_extra:line(
_pipe@30,
<<"fn coerce_dict(value: Dict(String, List(String))) -> Dict(String, dynamic.Dynamic)"/utf8>>
),
oaspec@util@string_extra:blank_line(_pipe@31);
false ->
Sb@3
end,
Sb@5 = case Has_form_urlencoded_body of
true ->
_pipe@32 = Sb@4,
_pipe@33 = oaspec@util@string_extra:line(
_pipe@32,
<<"fn form_url_decode(value: String) -> String {"/utf8>>
),
_pipe@34 = oaspec@util@string_extra:indent(
_pipe@33,
1,
<<"let value = string.replace(value, \"+\", \" \")"/utf8>>
),
_pipe@35 = oaspec@util@string_extra:indent(
_pipe@34,
1,
<<"case uri.percent_decode(value) { Ok(decoded) -> decoded Error(_) -> value }"/utf8>>
),
_pipe@36 = oaspec@util@string_extra:line(_pipe@35, <<"}"/utf8>>),
_pipe@37 = oaspec@util@string_extra:blank_line(_pipe@36),
_pipe@38 = oaspec@util@string_extra:line(
_pipe@37,
<<"fn parse_form_body(body: String) -> Dict(String, List(String)) {"/utf8>>
),
_pipe@39 = oaspec@util@string_extra:indent(
_pipe@38,
1,
<<"let parts = case body { \"\" -> [] _ -> string.split(body, \"&\") }"/utf8>>
),
_pipe@40 = oaspec@util@string_extra:indent(
_pipe@39,
1,
<<"list.fold(parts, dict.new(), fn(acc, part) {"/utf8>>
),
_pipe@41 = oaspec@util@string_extra:indent(
_pipe@40,
2,
<<"case part {"/utf8>>
),
_pipe@42 = oaspec@util@string_extra:indent(
_pipe@41,
3,
<<"\"\" -> acc"/utf8>>
),
_pipe@43 = oaspec@util@string_extra:indent(
_pipe@42,
3,
<<"_ ->"/utf8>>
),
_pipe@44 = oaspec@util@string_extra:indent(
_pipe@43,
4,
<<"case string.split_once(part, on: \"=\") {"/utf8>>
),
_pipe@45 = oaspec@util@string_extra:indent(
_pipe@44,
5,
<<"Ok(#(raw_key, raw_value)) -> {"/utf8>>
),
_pipe@46 = oaspec@util@string_extra:indent(
_pipe@45,
6,
<<"let key = form_url_decode(raw_key)"/utf8>>
),
_pipe@47 = oaspec@util@string_extra:indent(
_pipe@46,
6,
<<"let value = form_url_decode(raw_value)"/utf8>>
),
_pipe@48 = oaspec@util@string_extra:indent(
_pipe@47,
6,
<<"case dict.get(acc, key) {"/utf8>>
),
_pipe@49 = oaspec@util@string_extra:indent(
_pipe@48,
7,
<<"Ok(existing) -> dict.insert(acc, key, list.append(existing, [value]))"/utf8>>
),
_pipe@50 = oaspec@util@string_extra:indent(
_pipe@49,
7,
<<"Error(_) -> dict.insert(acc, key, [value])"/utf8>>
),
_pipe@51 = oaspec@util@string_extra:indent(
_pipe@50,
6,
<<"}"/utf8>>
),
_pipe@52 = oaspec@util@string_extra:indent(
_pipe@51,
5,
<<"}"/utf8>>
),
_pipe@53 = oaspec@util@string_extra:indent(
_pipe@52,
5,
<<"Error(_) -> {"/utf8>>
),
_pipe@54 = oaspec@util@string_extra:indent(
_pipe@53,
6,
<<"let key = form_url_decode(part)"/utf8>>
),
_pipe@55 = oaspec@util@string_extra:indent(
_pipe@54,
6,
<<"case dict.get(acc, key) {"/utf8>>
),
_pipe@56 = oaspec@util@string_extra:indent(
_pipe@55,
7,
<<"Ok(existing) -> dict.insert(acc, key, list.append(existing, [\"\"]))"/utf8>>
),
_pipe@57 = oaspec@util@string_extra:indent(
_pipe@56,
7,
<<"Error(_) -> dict.insert(acc, key, [\"\"])"/utf8>>
),
_pipe@58 = oaspec@util@string_extra:indent(
_pipe@57,
6,
<<"}"/utf8>>
),
_pipe@59 = oaspec@util@string_extra:indent(
_pipe@58,
5,
<<"}"/utf8>>
),
_pipe@60 = oaspec@util@string_extra:indent(
_pipe@59,
4,
<<"}"/utf8>>
),
_pipe@61 = oaspec@util@string_extra:indent(
_pipe@60,
2,
<<"}"/utf8>>
),
_pipe@62 = oaspec@util@string_extra:indent(
_pipe@61,
1,
<<"})"/utf8>>
),
_pipe@63 = oaspec@util@string_extra:line(_pipe@62, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@63);
false ->
Sb@4
end,
Sb@6 = case Has_multipart_body of
true ->
_pipe@64 = Sb@5,
_pipe@65 = oaspec@util@string_extra:line(
_pipe@64,
<<"fn multipart_boundary(headers: Dict(String, String)) -> Result(String, Nil) {"/utf8>>
),
_pipe@66 = oaspec@util@string_extra:indent(
_pipe@65,
1,
<<"case dict.get(headers, \"content-type\") {"/utf8>>
),
_pipe@67 = oaspec@util@string_extra:indent(
_pipe@66,
2,
<<"Ok(content_type) ->"/utf8>>
),
_pipe@68 = oaspec@util@string_extra:indent(
_pipe@67,
3,
<<"list.find_map(string.split(content_type, \";\"), fn(part) {"/utf8>>
),
_pipe@69 = oaspec@util@string_extra:indent(
_pipe@68,
4,
<<"let trimmed = string.trim(part)"/utf8>>
),
_pipe@70 = oaspec@util@string_extra:indent(
_pipe@69,
4,
<<"case string.starts_with(trimmed, \"boundary=\") {"/utf8>>
),
_pipe@71 = oaspec@util@string_extra:indent(
_pipe@70,
5,
<<"True -> Ok(string.replace(trimmed, \"boundary=\", \"\"))"/utf8>>
),
_pipe@72 = oaspec@util@string_extra:indent(
_pipe@71,
5,
<<"False -> Error(Nil)"/utf8>>
),
_pipe@73 = oaspec@util@string_extra:indent(
_pipe@72,
4,
<<"}"/utf8>>
),
_pipe@74 = oaspec@util@string_extra:indent(
_pipe@73,
3,
<<"})"/utf8>>
),
_pipe@75 = oaspec@util@string_extra:indent(
_pipe@74,
2,
<<"Error(_) -> Error(Nil)"/utf8>>
),
_pipe@76 = oaspec@util@string_extra:indent(
_pipe@75,
1,
<<"}"/utf8>>
),
_pipe@77 = oaspec@util@string_extra:line(_pipe@76, <<"}"/utf8>>),
_pipe@78 = oaspec@util@string_extra:blank_line(_pipe@77),
_pipe@79 = oaspec@util@string_extra:line(
_pipe@78,
<<"fn multipart_name(raw_headers: String) -> Result(String, Nil) {"/utf8>>
),
_pipe@80 = oaspec@util@string_extra:indent(
_pipe@79,
1,
<<"list.find_map(string.split(raw_headers, \"\\r\\n\"), fn(line) {"/utf8>>
),
_pipe@81 = oaspec@util@string_extra:indent(
_pipe@80,
2,
<<"case string.contains(line, \"name=\") {"/utf8>>
),
_pipe@82 = oaspec@util@string_extra:indent(
_pipe@81,
3,
<<"True ->"/utf8>>
),
_pipe@83 = oaspec@util@string_extra:indent(
_pipe@82,
4,
<<"list.find_map(string.split(line, \";\"), fn(part) {"/utf8>>
),
_pipe@84 = oaspec@util@string_extra:indent(
_pipe@83,
5,
<<"let trimmed = string.trim(part)"/utf8>>
),
_pipe@85 = oaspec@util@string_extra:indent(
_pipe@84,
5,
<<"case string.starts_with(trimmed, \"name=\") {"/utf8>>
),
_pipe@86 = oaspec@util@string_extra:indent(
_pipe@85,
6,
<<"True -> Ok(string.replace(string.replace(trimmed, \"name=\", \"\"), \"\\\"\", \"\"))"/utf8>>
),
_pipe@87 = oaspec@util@string_extra:indent(
_pipe@86,
6,
<<"False -> Error(Nil)"/utf8>>
),
_pipe@88 = oaspec@util@string_extra:indent(
_pipe@87,
5,
<<"}"/utf8>>
),
_pipe@89 = oaspec@util@string_extra:indent(
_pipe@88,
4,
<<"})"/utf8>>
),
_pipe@90 = oaspec@util@string_extra:indent(
_pipe@89,
3,
<<"False -> Error(Nil)"/utf8>>
),
_pipe@91 = oaspec@util@string_extra:indent(
_pipe@90,
2,
<<"}"/utf8>>
),
_pipe@92 = oaspec@util@string_extra:indent(
_pipe@91,
1,
<<"})"/utf8>>
),
_pipe@93 = oaspec@util@string_extra:line(_pipe@92, <<"}"/utf8>>),
_pipe@94 = oaspec@util@string_extra:blank_line(_pipe@93),
_pipe@95 = oaspec@util@string_extra:line(
_pipe@94,
<<"fn parse_multipart_body(body: String, headers: Dict(String, String)) -> Dict(String, List(String)) {"/utf8>>
),
_pipe@96 = oaspec@util@string_extra:indent(
_pipe@95,
1,
<<"case multipart_boundary(headers) {"/utf8>>
),
_pipe@97 = oaspec@util@string_extra:indent(
_pipe@96,
2,
<<"Ok(boundary) -> {"/utf8>>
),
_pipe@98 = oaspec@util@string_extra:indent(
_pipe@97,
3,
<<"let delimiter = \"--\" <> boundary"/utf8>>
),
_pipe@99 = oaspec@util@string_extra:indent(
_pipe@98,
3,
<<"let parts = string.split(body, delimiter)"/utf8>>
),
_pipe@100 = oaspec@util@string_extra:indent(
_pipe@99,
3,
<<"list.fold(parts, dict.new(), fn(acc, part) {"/utf8>>
),
_pipe@101 = oaspec@util@string_extra:indent(
_pipe@100,
4,
<<"let normalized_part = part |> string.remove_prefix(\"\\r\\n\") |> string.remove_suffix(\"\\r\\n\")"/utf8>>
),
_pipe@102 = oaspec@util@string_extra:indent(
_pipe@101,
4,
<<"case normalized_part == \"\" || normalized_part == \"--\" {"/utf8>>
),
_pipe@103 = oaspec@util@string_extra:indent(
_pipe@102,
5,
<<"True -> acc"/utf8>>
),
_pipe@104 = oaspec@util@string_extra:indent(
_pipe@103,
5,
<<"False ->"/utf8>>
),
_pipe@105 = oaspec@util@string_extra:indent(
_pipe@104,
6,
<<"case string.split_once(normalized_part, on: \"\\r\\n\\r\\n\") {"/utf8>>
),
_pipe@106 = oaspec@util@string_extra:indent(
_pipe@105,
7,
<<"Ok(#(raw_part_headers, raw_value)) ->"/utf8>>
),
_pipe@107 = oaspec@util@string_extra:indent(
_pipe@106,
8,
<<"case multipart_name(raw_part_headers) {"/utf8>>
),
_pipe@108 = oaspec@util@string_extra:indent(
_pipe@107,
9,
<<"Ok(name) -> {"/utf8>>
),
_pipe@109 = oaspec@util@string_extra:indent(
_pipe@108,
10,
<<"let value = raw_value"/utf8>>
),
_pipe@110 = oaspec@util@string_extra:indent(
_pipe@109,
10,
<<"case dict.get(acc, name) {"/utf8>>
),
_pipe@111 = oaspec@util@string_extra:indent(
_pipe@110,
11,
<<"Ok(existing) -> dict.insert(acc, name, list.append(existing, [value]))"/utf8>>
),
_pipe@112 = oaspec@util@string_extra:indent(
_pipe@111,
11,
<<"Error(_) -> dict.insert(acc, name, [value])"/utf8>>
),
_pipe@113 = oaspec@util@string_extra:indent(
_pipe@112,
10,
<<"}"/utf8>>
),
_pipe@114 = oaspec@util@string_extra:indent(
_pipe@113,
9,
<<"}"/utf8>>
),
_pipe@115 = oaspec@util@string_extra:indent(
_pipe@114,
9,
<<"Error(_) -> acc"/utf8>>
),
_pipe@116 = oaspec@util@string_extra:indent(
_pipe@115,
8,
<<"}"/utf8>>
),
_pipe@117 = oaspec@util@string_extra:indent(
_pipe@116,
7,
<<"Error(_) -> acc"/utf8>>
),
_pipe@118 = oaspec@util@string_extra:indent(
_pipe@117,
6,
<<"}"/utf8>>
),
_pipe@119 = oaspec@util@string_extra:indent(
_pipe@118,
4,
<<"}"/utf8>>
),
_pipe@120 = oaspec@util@string_extra:indent(
_pipe@119,
3,
<<"})"/utf8>>
),
_pipe@121 = oaspec@util@string_extra:indent(
_pipe@120,
2,
<<"}"/utf8>>
),
_pipe@122 = oaspec@util@string_extra:indent(
_pipe@121,
2,
<<"Error(_) -> dict.new()"/utf8>>
),
_pipe@123 = oaspec@util@string_extra:indent(
_pipe@122,
1,
<<"}"/utf8>>
),
_pipe@124 = oaspec@util@string_extra:line(_pipe@123, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@124);
false ->
Sb@5
end,
Sb@7 = case Has_nested_form_urlencoded_body of
true ->
_pipe@125 = Sb@6,
_pipe@126 = oaspec@util@string_extra:line(
_pipe@125,
<<"fn form_object_present(form_body: Dict(String, List(String)), prefix: String, props: List(String)) -> Bool {"/utf8>>
),
_pipe@127 = oaspec@util@string_extra:indent(
_pipe@126,
1,
<<"list.any(props, fn(prop) { dict.has_key(form_body, prefix <> \"[\" <> prop <> \"]\") })"/utf8>>
),
_pipe@128 = oaspec@util@string_extra:line(_pipe@127, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@128);
false ->
Sb@6
end,
Sb@8 = begin
_pipe@129 = Sb@7,
_pipe@130 = oaspec@util@string_extra:doc_comment(
_pipe@129,
<<"Route an incoming request to the appropriate handler."/utf8>>
),
_pipe@131 = oaspec@util@string_extra:line(
_pipe@130,
<<<<<<<<<<<<"pub fn route(method: String, path: List(String), "/utf8,
(route_arg_name(
<<"query"/utf8>>,
Uses_query
))/binary>>/binary,
": Dict(String, List(String)), "/utf8>>/binary,
(route_arg_name(<<"headers"/utf8>>, Uses_headers))/binary>>/binary,
": Dict(String, String), "/utf8>>/binary,
(route_arg_name(<<"body"/utf8>>, Uses_body))/binary>>/binary,
": String) -> ServerResponse {"/utf8>>
),
oaspec@util@string_extra:indent(
_pipe@131,
1,
<<"case method, path {"/utf8>>
)
end,
Sb@10 = gleam@list:fold(
Operations,
Sb@8,
fun(Sb@9, Op@21) ->
{Op_id, Operation@21, Path, Method} = Op@21,
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@21)
)
orelse gleam@option:is_some(erlang:element(7, Operation@21)),
_pipe@132 = Sb@9,
_pipe@133 = oaspec@util@string_extra:indent(
_pipe@132,
2,
<<<<<<<<"\""/utf8, Method_str/binary>>/binary, "\", "/utf8>>/binary,
Path_pattern/binary>>/binary,
" -> {"/utf8>>
),
_pipe@134 = generate_route_body(
_pipe@133,
Op_id,
Fn_name,
Operation@21,
Path,
Has_params,
Ctx
),
oaspec@util@string_extra:indent(_pipe@134, 2, <<"}"/utf8>>)
end
),
Sb@11 = begin
_pipe@135 = Sb@10,
_pipe@136 = oaspec@util@string_extra:indent(
_pipe@135,
2,
<<"_, _ -> ServerResponse(status: 404, body: \"Not Found\", headers: [])"/utf8>>
),
_pipe@137 = oaspec@util@string_extra:indent(_pipe@136, 1, <<"}"/utf8>>),
_pipe@138 = oaspec@util@string_extra:line(_pipe@137, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@138)
end,
Sb@12 = case Needs_cookie_lookup of
true ->
generate_cookie_lookup(Sb@11);
false ->
Sb@11
end,
oaspec@util@string_extra:to_string(Sb@12).
-file("src/oaspec/codegen/server.gleam", 20).
?DOC(" Generate server stub files.\n").
-spec generate(oaspec@codegen@context:context()) -> list(oaspec@codegen@context:generated_file()).
generate(Ctx) ->
Operations = oaspec@openapi@operations:collect_operations(Ctx),
Handlers_content = generate_handlers(Ctx, Operations),
Router_content = generate_router(Ctx, Operations),
[{generated_file,
<<"handlers.gleam"/utf8>>,
Handlers_content,
server_target},
{generated_file, <<"router.gleam"/utf8>>, Router_content, server_target}].