Packages
oaspec
0.19.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", 126).
?DOC(" Generate a single delegator function in `handlers_generated.gleam`.\n").
-spec generate_handler_delegator(
gleam@string_tree:string_tree(),
binary(),
oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved())
) -> gleam@string_tree:string_tree().
generate_handler_delegator(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>>,
Has_params = not gleam@list:is_empty(erlang:element(6, Operation)) orelse gleam@option:is_some(
erlang:element(7, Operation)
),
case Has_params of
true ->
_pipe = Sb,
_pipe@1 = oaspec@util@string_extra:line(
_pipe,
<<<<<<<<<<<<"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>>
),
_pipe@2 = oaspec@util@string_extra:indent(
_pipe@1,
1,
<<<<"handlers."/utf8, Fn_name/binary>>/binary, "(req)"/utf8>>
),
_pipe@3 = oaspec@util@string_extra:line(_pipe@2, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@3);
false ->
_pipe@4 = Sb,
_pipe@5 = oaspec@util@string_extra:line(
_pipe@4,
<<<<<<<<"pub fn "/utf8, Fn_name/binary>>/binary,
"() -> response_types."/utf8>>/binary,
Response_type/binary>>/binary,
" {"/utf8>>
),
_pipe@6 = oaspec@util@string_extra:indent(
_pipe@5,
1,
<<<<"handlers."/utf8, Fn_name/binary>>/binary, "()"/utf8>>
),
_pipe@7 = oaspec@util@string_extra:line(_pipe@6, <<"}"/utf8>>),
oaspec@util@string_extra:blank_line(_pipe@7)
end.
-file("src/oaspec/codegen/server.gleam", 103).
?DOC(
" Generate `handlers_generated.gleam`, a sealed delegator that the\n"
" router imports. Each operation forwards to `handlers.<op_name>(req)`.\n"
" Issue #247: this file carries the `// DO NOT EDIT` banner and is\n"
" always overwritten so router/handler wiring stays in sync with the\n"
" spec without touching the user's `handlers.gleam`.\n"
).
-spec generate_handlers_generated(
oaspec@codegen@context:context(),
list({binary(),
oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved()),
binary(),
oaspec@openapi@spec:http_method()})
) -> binary().
generate_handlers_generated(Ctx, Operations) ->
Pkg = oaspec@config:package(oaspec@codegen@context:config(Ctx)),
Sb = begin
_pipe = oaspec@util@string_extra:file_header(<<"0.19.0"/utf8>>),
oaspec@util@string_extra:imports(
_pipe,
[<<Pkg/binary, "/handlers"/utf8>>,
<<Pkg/binary, "/request_types"/utf8>>,
<<Pkg/binary, "/response_types"/utf8>>]
)
end,
Sb@2 = gleam@list:fold(
Operations,
Sb,
fun(Sb@1, Op) ->
{Op_id, Operation, _, _} = Op,
generate_handler_delegator(Sb@1, Op_id, Operation)
end
),
oaspec@util@string_extra:to_string(Sb@2).
-file("src/oaspec/codegen/server.gleam", 166).
?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", 64).
?DOC(
" Generate the user-owned `handlers.gleam`. Emitted only on first\n"
" generation; the writer's `SkipIfExists` mode prevents subsequent\n"
" runs from clobbering the user's implementation. The `// DO NOT EDIT`\n"
" banner is intentionally absent — the user owns this file.\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:line(
oaspec@util@string_extra:new(),
<<"//// Implement these handler functions. This file is emitted once"/utf8>>
),
_pipe@1 = oaspec@util@string_extra:line(
_pipe,
<<"//// by `oaspec generate` and skipped on subsequent runs, so your"/utf8>>
),
_pipe@2 = oaspec@util@string_extra:line(
_pipe@1,
<<"//// edits survive regeneration. Router wiring lives in"/utf8>>
),
_pipe@3 = oaspec@util@string_extra:line(
_pipe@2,
<<"//// `handlers_generated.gleam`, which delegates here."/utf8>>
),
_pipe@4 = oaspec@util@string_extra:blank_line(_pipe@3),
oaspec@util@string_extra:imports(
_pipe@4,
[<<(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", 919).
-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", 924).
-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", 1239).
?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", 1423).
?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>>;
{inline, {string_schema, _, _, _, _, _, _}} ->
<<"fn(items) { json.array(items, json.string) }"/utf8>>;
{inline, {integer_schema, _, _, _, _, _, _, _}} ->
<<"fn(items) { json.array(items, json.int) }"/utf8>>;
{inline, {number_schema, _, _, _, _, _, _, _}} ->
<<"fn(items) { json.array(items, json.float) }"/utf8>>;
{inline, {boolean_schema, _}} ->
<<"fn(items) { json.array(items, json.bool) }"/utf8>>;
_ ->
<<"fn(items) { json.array(items, 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", 1269).
?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", 990).
?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
),
Deduped_field_names = oaspec@openapi@dedup:dedup_param_field_names(Params),
Params_with_field_names = gleam@list:zip(Params, Deduped_field_names),
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_with_field_names,
Sb@6,
fun(Sb@7, Entry@1) ->
{Param, Field_name} = Entry@1,
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_generated."/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", 950).
?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_generated."/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", 1485).
?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", 1493).
?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", 1464).
?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", 220).
?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_generated"/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.19.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", 32).
?DOC(
" Generate server stub files.\n"
"\n"
" Issue #247 splits the handler surface in two:\n"
"\n"
" - `handlers.gleam` carries user-editable panic stubs and is emitted\n"
" only on first generation (`SkipIfExists`). Re-running\n"
" `oaspec generate` leaves it alone, so user implementations\n"
" survive regeneration.\n"
" - `handlers_generated.gleam` is a sealed delegator that `router.gleam`\n"
" imports. Each operation forwards to `handlers.<op_name>(req)`. It\n"
" is always overwritten so the wiring stays in lock-step with the\n"
" spec.\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),
Handlers_generated_content = generate_handlers_generated(Ctx, Operations),
Router_content = generate_router(Ctx, Operations),
[{generated_file,
<<"handlers.gleam"/utf8>>,
Handlers_content,
server_target,
skip_if_exists},
{generated_file,
<<"handlers_generated.gleam"/utf8>>,
Handlers_generated_content,
server_target,
overwrite},
{generated_file,
<<"router.gleam"/utf8>>,
Router_content,
server_target,
overwrite}].