Packages

OpenAPI code generation for Gleam — parse specs, generate types, routes, clients, and React Query/SWR hooks

Current section

Files

Jump to
nori src nori@codegen@templates.erl
Raw

src/nori@codegen@templates.erl

-module(nori@codegen@templates).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/nori/codegen/templates.gleam").
-export([render/2, ir_to_ts_react_query_context/1, ir_to_ts_swr_context/1, ir_to_ts_client_context/1, ir_to_ts_types_context/2, load_template/2]).
-export_type([ts_config/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Template-based code generation using the handles library.\n"
"\n"
" Stores default templates and provides IR-to-context converters\n"
" for TypeScript code generators.\n"
).
-type ts_config() :: {ts_config, boolean(), boolean(), boolean()}.
-file("src/nori/codegen/templates.gleam", 107).
?DOC(
" Compile and run a handles template with the given context.\n"
" Panics on template compilation or runtime errors (templates are constants\n"
" so compilation errors are programming bugs).\n"
).
-spec render(binary(), handles@ctx:value()) -> binary().
render(Template_str, Context) ->
Tmpl@1 = case handles:prepare(Template_str) of
{ok, Tmpl} -> Tmpl;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"nori/codegen/templates"/utf8>>,
function => <<"render"/utf8>>,
line => 108,
value => _assert_fail,
start => 3872,
'end' => 3923,
pattern_start => 3883,
pattern_end => 3891})
end,
Result@1 = case handles:run(Tmpl@1, Context, []) of
{ok, Result} -> Result;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"nori/codegen/templates"/utf8>>,
function => <<"render"/utf8>>,
line => 109,
value => _assert_fail@1,
start => 3926,
'end' => 3980,
pattern_start => 3937,
pattern_end => 3947})
end,
unicode:characters_to_binary(Result@1).
-file("src/nori/codegen/templates.gleam", 302).
?DOC(
" True if any security scheme places an API key in a cookie. Generated TS\n"
" fetch calls then default to `credentials: \"include\"` so browsers send the\n"
" session cookie cross-origin.\n"
).
-spec has_cookie_auth(nori@codegen@ir:codegen_i_r()) -> boolean().
has_cookie_auth(Ir) ->
gleam@list:any(erlang:element(7, Ir), fun(S) -> case S of
{api_key_auth, _, _, in_cookie} ->
true;
_ ->
false
end end).
-file("src/nori/codegen/templates.gleam", 378).
-spec build_client_param_list(
list(nori@codegen@ir:endpoint_param()),
list(nori@codegen@ir:endpoint_param()),
gleam@option:option(nori@codegen@ir:request_body_i_r())
) -> binary().
build_client_param_list(Path_params, Query_params, Body) ->
Path_param_strs = begin
_pipe = Path_params,
gleam@list:map(
_pipe,
fun(P) ->
<<<<(erlang:element(2, P))/binary, ": "/utf8>>/binary,
(nori@codegen@typescript@shared:type_ref_to_ts(
erlang:element(4, P)
))/binary>>
end
)
end,
Query_param_strs = case Query_params of
[] ->
[];
Params ->
Fields = begin
_pipe@1 = Params,
_pipe@2 = gleam@list:map(
_pipe@1,
fun(P@1) ->
Opt = case erlang:element(5, P@1) of
true ->
<<""/utf8>>;
false ->
<<"?"/utf8>>
end,
<<<<<<(erlang:element(2, P@1))/binary, Opt/binary>>/binary,
": "/utf8>>/binary,
(nori@codegen@typescript@shared:type_ref_to_ts(
erlang:element(4, P@1)
))/binary>>
end
),
gleam@string:join(_pipe@2, <<"; "/utf8>>)
end,
[<<<<"params: { "/utf8, Fields/binary>>/binary, " }"/utf8>>]
end,
Body_param_strs = case Body of
{some, {request_body_i_r, _, Type_ref, _}} ->
[<<"body: "/utf8,
(nori@codegen@typescript@shared:type_ref_to_ts(Type_ref))/binary>>];
none ->
[]
end,
_pipe@3 = [Path_param_strs, Query_param_strs, Body_param_strs],
_pipe@4 = lists:append(_pipe@3),
gleam@string:join(_pipe@4, <<", "/utf8>>).
-file("src/nori/codegen/templates.gleam", 416).
-spec build_url_expression(
binary(),
list(nori@codegen@ir:endpoint_param()),
list(nori@codegen@ir:endpoint_param())
) -> binary().
build_url_expression(Path, Path_params, Query_params) ->
Url_template = begin
_pipe = Path_params,
gleam@list:fold(
_pipe,
Path,
fun(P, Param) ->
gleam@string:replace(
P,
<<<<"{"/utf8, (erlang:element(2, Param))/binary>>/binary,
"}"/utf8>>,
<<<<"${"/utf8, (erlang:element(2, Param))/binary>>/binary,
"}"/utf8>>
)
end
)
end,
Base = <<<<" const url = `${_config.baseUrl}"/utf8, Url_template/binary>>/binary,
"`;\n"/utf8>>,
case Query_params of
[] ->
Base;
_ ->
Base_line = <<<<" const _url = new URL(`${_config.baseUrl}"/utf8,
Url_template/binary>>/binary,
"`);\n"/utf8>>,
Param_lines = begin
_pipe@1 = Query_params,
_pipe@2 = gleam@list:map(
_pipe@1,
fun(P@1) -> case erlang:element(5, P@1) of
true ->
<<<<<<<<" _url.searchParams.set(\""/utf8,
(erlang:element(2, P@1))/binary>>/binary,
"\", String(params."/utf8>>/binary,
(erlang:element(2, P@1))/binary>>/binary,
"));\n"/utf8>>;
false ->
<<<<<<<<<<<<" if (params."/utf8,
(erlang:element(2, P@1))/binary>>/binary,
" !== undefined) _url.searchParams.set(\""/utf8>>/binary,
(erlang:element(2, P@1))/binary>>/binary,
"\", String(params."/utf8>>/binary,
(erlang:element(2, P@1))/binary>>/binary,
"));\n"/utf8>>
end end
),
gleam@string:join(_pipe@2, <<""/utf8>>)
end,
Url_line = <<" const url = _url.toString();\n"/utf8>>,
<<<<Base_line/binary, Param_lines/binary>>/binary, Url_line/binary>>
end.
-file("src/nori/codegen/templates.gleam", 461).
-spec build_fetch_options(
gleam@option:option(nori@codegen@ir:request_body_i_r())
) -> binary().
build_fetch_options(Body) ->
case Body of
{some, _} ->
<<" body: JSON.stringify(body),\n"/utf8>>;
none ->
<<""/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 468).
-spec build_response_handling(binary()) -> binary().
build_response_handling(Return_type) ->
case Return_type of
<<"void"/utf8>> ->
<<" return;\n"/utf8>>;
_ ->
<<<<" return await response.json() as "/utf8, Return_type/binary>>/binary,
";\n"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 751).
-spec build_swr_mutation_arg_type(
list(nori@codegen@ir:endpoint_param()),
nori@codegen@ir:endpoint()
) -> binary().
build_swr_mutation_arg_type(Path_params, Endpoint) ->
Body_type = case erlang:element(9, Endpoint) of
{some, {request_body_i_r, _, Type_ref, _}} ->
[<<" body: "/utf8,
(nori@codegen@typescript@shared:type_ref_to_ts(Type_ref))/binary>>];
none ->
[]
end,
Path_fields = begin
_pipe = Path_params,
gleam@list:map(
_pipe,
fun(P) ->
<<<<<<" "/utf8, (erlang:element(2, P))/binary>>/binary,
": "/utf8>>/binary,
(nori@codegen@typescript@shared:type_ref_to_ts(
erlang:element(4, P)
))/binary>>
end
)
end,
All_fields = lists:append(Path_fields, Body_type),
case All_fields of
[] ->
<<"void"/utf8>>;
Fields ->
<<<<"{"/utf8, (gleam@string:join(Fields, <<";"/utf8>>))/binary>>/binary,
" }"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 776).
-spec build_swr_mutation_trigger(
binary(),
list(nori@codegen@ir:endpoint_param()),
nori@codegen@ir:endpoint()
) -> binary().
build_swr_mutation_trigger(Fn_name, Path_params, Endpoint) ->
Arg_type = build_swr_mutation_arg_type(Path_params, Endpoint),
case Arg_type of
<<"void"/utf8>> ->
<<<<") => "/utf8, Fn_name/binary>>/binary, "()"/utf8>>;
_ ->
Args = begin
_pipe@1 = lists:append(
begin
_pipe = Path_params,
gleam@list:map(
_pipe,
fun(P) ->
<<"arg."/utf8, (erlang:element(2, P))/binary>>
end
)
end,
case erlang:element(9, Endpoint) of
{some, _} ->
[<<"arg.body"/utf8>>];
none ->
[]
end
),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end,
<<<<<<<<") => "/utf8, Fn_name/binary>>/binary, "("/utf8>>/binary,
Args/binary>>/binary,
")"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 814).
-spec generate_type_imports(nori@codegen@ir:codegen_i_r()) -> binary().
generate_type_imports(Ir) ->
Type_names = begin
_pipe = erlang:element(5, Ir),
gleam@list:map(_pipe, fun(Td) -> case Td of
{record_type, Name, _, _} ->
Name;
{enum_type, Name@1, _, _} ->
Name@1;
{union_type, Name@2, _, _, _} ->
Name@2;
{alias_type, Name@3, _, _} ->
Name@3
end end)
end,
case Type_names of
[] ->
<<""/utf8>>;
Names ->
<<<<"import type { "/utf8,
(gleam@string:join(Names, <<", "/utf8>>))/binary>>/binary,
" } from \"./types.generated\";"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 835).
-spec generate_client_imports(nori@codegen@ir:codegen_i_r()) -> binary().
generate_client_imports(Ir) ->
Fn_names = begin
_pipe = erlang:element(6, Ir),
gleam@list:map(
_pipe,
fun(E) ->
nori@codegen@typescript@shared:to_camel_case(
erlang:element(2, E)
)
end
)
end,
case Fn_names of
[] ->
<<""/utf8>>;
Names ->
<<<<"import { "/utf8,
(gleam@string:join(Names, <<", "/utf8>>))/binary>>/binary,
" } from \"./client.generated\";"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 849).
-spec build_hook_params(
list(nori@codegen@ir:endpoint_param()),
list(nori@codegen@ir:endpoint_param())
) -> binary().
build_hook_params(Path_params, Query_params) ->
Path_strs = begin
_pipe = Path_params,
gleam@list:map(
_pipe,
fun(P) ->
<<<<(erlang:element(2, P))/binary, ": "/utf8>>/binary,
(nori@codegen@typescript@shared:type_ref_to_ts(
erlang:element(4, P)
))/binary>>
end
)
end,
Query_strs = case Query_params of
[] ->
[];
Params ->
Fields = begin
_pipe@1 = Params,
_pipe@2 = gleam@list:map(
_pipe@1,
fun(P@1) ->
Opt = case erlang:element(5, P@1) of
true ->
<<""/utf8>>;
false ->
<<"?"/utf8>>
end,
<<<<<<(erlang:element(2, P@1))/binary, Opt/binary>>/binary,
": "/utf8>>/binary,
(nori@codegen@typescript@shared:type_ref_to_ts(
erlang:element(4, P@1)
))/binary>>
end
),
gleam@string:join(_pipe@2, <<"; "/utf8>>)
end,
[<<<<"params: { "/utf8, Fields/binary>>/binary, " }"/utf8>>]
end,
_pipe@3 = lists:append(Path_strs, Query_strs),
gleam@string:join(_pipe@3, <<", "/utf8>>).
-file("src/nori/codegen/templates.gleam", 878).
-spec build_call_args(
list(nori@codegen@ir:endpoint_param()),
list(nori@codegen@ir:endpoint_param())
) -> binary().
build_call_args(Path_params, Query_params) ->
Path_args = begin
_pipe = Path_params,
gleam@list:map(_pipe, fun(P) -> erlang:element(2, P) end)
end,
Query_args = case Query_params of
[] ->
[];
_ ->
[<<"params"/utf8>>]
end,
_pipe@1 = lists:append(Path_args, Query_args),
gleam@string:join(_pipe@1, <<", "/utf8>>).
-file("src/nori/codegen/templates.gleam", 905).
-spec build_mutation_variables_type(
list(nori@codegen@ir:endpoint_param()),
nori@codegen@ir:endpoint()
) -> binary().
build_mutation_variables_type(Path_params, Endpoint) ->
Body_type = case erlang:element(9, Endpoint) of
{some, {request_body_i_r, _, Type_ref, _}} ->
[<<" body: "/utf8,
(nori@codegen@typescript@shared:type_ref_to_ts(Type_ref))/binary>>];
none ->
[]
end,
Path_fields = begin
_pipe = Path_params,
gleam@list:map(
_pipe,
fun(P) ->
<<<<<<" "/utf8, (erlang:element(2, P))/binary>>/binary,
": "/utf8>>/binary,
(nori@codegen@typescript@shared:type_ref_to_ts(
erlang:element(4, P)
))/binary>>
end
)
end,
All_fields = lists:append(Path_fields, Body_type),
case All_fields of
[] ->
<<"void"/utf8>>;
Fields ->
<<<<"{"/utf8, (gleam@string:join(Fields, <<";"/utf8>>))/binary>>/binary,
" }"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 930).
-spec build_mutation_fn(
binary(),
list(nori@codegen@ir:endpoint_param()),
nori@codegen@ir:endpoint()
) -> binary().
build_mutation_fn(Fn_name, Path_params, Endpoint) ->
Vars_type = build_mutation_variables_type(Path_params, Endpoint),
case Vars_type of
<<"void"/utf8>> ->
<<<<") => "/utf8, Fn_name/binary>>/binary, "()"/utf8>>;
_ ->
Args = begin
_pipe@1 = lists:append(
begin
_pipe = Path_params,
gleam@list:map(
_pipe,
fun(P) ->
<<"vars."/utf8, (erlang:element(2, P))/binary>>
end
)
end,
case erlang:element(9, Endpoint) of
{some, _} ->
[<<"vars.body"/utf8>>];
none ->
[]
end
),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end,
<<<<<<<<"vars) => "/utf8, Fn_name/binary>>/binary, "("/utf8>>/binary,
Args/binary>>/binary,
")"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 953).
-spec get_response_type(list(nori@codegen@ir:response_i_r())) -> binary().
get_response_type(Responses) ->
Success = begin
_pipe = Responses,
gleam@list:find(
_pipe,
fun(R) ->
gleam_stdlib:string_starts_with(
erlang:element(2, R),
<<"2"/utf8>>
)
end
)
end,
case Success of
{ok, {response_i_r, _, _, _, {some, Type_ref}}} ->
nori@codegen@typescript@shared:type_ref_to_ts(Type_ref);
_ ->
<<"void"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 965).
-spec get_params_by_location(
list(nori@codegen@ir:endpoint_param()),
nori@codegen@ir:param_location()
) -> list(nori@codegen@ir:endpoint_param()).
get_params_by_location(Params, Location) ->
_pipe = Params,
gleam@list:filter(_pipe, fun(P) -> erlang:element(3, P) =:= Location end).
-file("src/nori/codegen/templates.gleam", 605).
-spec generate_rq_mutation_hook(nori@codegen@ir:endpoint()) -> binary().
generate_rq_mutation_hook(Endpoint) ->
Hook_name = <<"use"/utf8,
(nori@codegen@typescript@shared:to_pascal_case(
erlang:element(2, Endpoint)
))/binary>>,
Fn_name = nori@codegen@typescript@shared:to_camel_case(
erlang:element(2, Endpoint)
),
Return_type = get_response_type(erlang:element(10, Endpoint)),
Path_params = get_params_by_location(
erlang:element(8, Endpoint),
path_param
),
Vars_type = build_mutation_variables_type(Path_params, Endpoint),
Mutation_fn = build_mutation_fn(Fn_name, Path_params, Endpoint),
Summary_comment = case erlang:element(5, Endpoint) of
{some, S} ->
<<<<"/** "/utf8, S/binary>>/binary, " */\n"/utf8>>;
none ->
<<""/utf8>>
end,
<<<<<<<<<<<<<<<<<<<<<<<<<<Summary_comment/binary, "export function "/utf8>>/binary,
Hook_name/binary>>/binary,
"() {\n"/utf8>>/binary,
" return useMutation<"/utf8>>/binary,
Return_type/binary>>/binary,
", Error, "/utf8>>/binary,
Vars_type/binary>>/binary,
">({\n"/utf8>>/binary,
" mutationFn: ("/utf8>>/binary,
Mutation_fn/binary>>/binary,
",\n"/utf8>>/binary,
" });\n"/utf8>>/binary,
"}"/utf8>>.
-file("src/nori/codegen/templates.gleam", 721).
-spec generate_swr_mutation_hook(nori@codegen@ir:endpoint()) -> binary().
generate_swr_mutation_hook(Endpoint) ->
Hook_name = <<"use"/utf8,
(nori@codegen@typescript@shared:to_pascal_case(
erlang:element(2, Endpoint)
))/binary>>,
Fn_name = nori@codegen@typescript@shared:to_camel_case(
erlang:element(2, Endpoint)
),
Return_type = get_response_type(erlang:element(10, Endpoint)),
Path_params = get_params_by_location(
erlang:element(8, Endpoint),
path_param
),
Vars_type = build_swr_mutation_arg_type(Path_params, Endpoint),
Trigger_body = build_swr_mutation_trigger(Fn_name, Path_params, Endpoint),
Summary_comment = case erlang:element(5, Endpoint) of
{some, S} ->
<<<<"/** "/utf8, S/binary>>/binary, " */\n"/utf8>>;
none ->
<<""/utf8>>
end,
<<<<<<<<<<<<<<<<<<<<<<<<<<Summary_comment/binary, "export function "/utf8>>/binary,
Hook_name/binary>>/binary,
"() {\n"/utf8>>/binary,
" return useSWRMutation<"/utf8>>/binary,
Return_type/binary>>/binary,
", Error, string, "/utf8>>/binary,
Vars_type/binary>>/binary,
">(\""/utf8>>/binary,
(erlang:element(2, Endpoint))/binary>>/binary,
"\", (_key, { arg }"/utf8>>/binary,
Trigger_body/binary>>/binary,
");\n"/utf8>>/binary,
"}"/utf8>>.
-file("src/nori/codegen/templates.gleam", 799).
-spec build_swr_key(nori@codegen@ir:endpoint()) -> binary().
build_swr_key(Endpoint) ->
Path_params = get_params_by_location(
erlang:element(8, Endpoint),
path_param
),
case Path_params of
[] ->
<<<<"\""/utf8, (erlang:element(2, Endpoint))/binary>>/binary,
"\""/utf8>>;
Params ->
Parts = begin
_pipe = Params,
_pipe@1 = gleam@list:map(
_pipe,
fun(P) -> erlang:element(2, P) end
),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end,
<<<<<<<<"[\""/utf8, (erlang:element(2, Endpoint))/binary>>/binary,
"\", "/utf8>>/binary,
Parts/binary>>/binary,
"]"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 686).
-spec generate_swr_query_hook(nori@codegen@ir:endpoint()) -> binary().
generate_swr_query_hook(Endpoint) ->
Hook_name = <<"use"/utf8,
(nori@codegen@typescript@shared:to_pascal_case(
erlang:element(2, Endpoint)
))/binary>>,
Fn_name = nori@codegen@typescript@shared:to_camel_case(
erlang:element(2, Endpoint)
),
Return_type = get_response_type(erlang:element(10, Endpoint)),
Path_params = get_params_by_location(
erlang:element(8, Endpoint),
path_param
),
Query_params = get_params_by_location(
erlang:element(8, Endpoint),
query_param
),
Params = build_hook_params(Path_params, Query_params),
Call_args = build_call_args(Path_params, Query_params),
Swr_key = build_swr_key(Endpoint),
Summary_comment = case erlang:element(5, Endpoint) of
{some, S} ->
<<<<"/** "/utf8, S/binary>>/binary, " */\n"/utf8>>;
none ->
<<""/utf8>>
end,
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Summary_comment/binary,
"export function "/utf8>>/binary,
Hook_name/binary>>/binary,
"("/utf8>>/binary,
Params/binary>>/binary,
") {\n"/utf8>>/binary,
" return useSWR<"/utf8>>/binary,
Return_type/binary>>/binary,
">("/utf8>>/binary,
Swr_key/binary>>/binary,
", () => "/utf8>>/binary,
Fn_name/binary>>/binary,
"("/utf8>>/binary,
Call_args/binary>>/binary,
"));\n"/utf8>>/binary,
"}"/utf8>>.
-file("src/nori/codegen/templates.gleam", 679).
-spec generate_swr_hook(nori@codegen@ir:endpoint()) -> binary().
generate_swr_hook(Endpoint) ->
case erlang:element(3, Endpoint) of
get ->
generate_swr_query_hook(Endpoint);
_ ->
generate_swr_mutation_hook(Endpoint)
end.
-file("src/nori/codegen/templates.gleam", 892).
-spec build_query_key(nori@codegen@ir:endpoint()) -> binary().
build_query_key(Endpoint) ->
Path_params = get_params_by_location(
erlang:element(8, Endpoint),
path_param
),
Key_parts = case Path_params of
[] ->
<<<<"\""/utf8, (erlang:element(2, Endpoint))/binary>>/binary,
"\""/utf8>>;
Params ->
Param_parts = begin
_pipe = Params,
_pipe@1 = gleam@list:map(
_pipe,
fun(P) -> erlang:element(2, P) end
),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end,
<<<<<<"\""/utf8, (erlang:element(2, Endpoint))/binary>>/binary,
"\", "/utf8>>/binary,
Param_parts/binary>>
end,
<<<<"["/utf8, Key_parts/binary>>/binary, "]"/utf8>>.
-file("src/nori/codegen/templates.gleam", 567).
-spec generate_rq_query_hook(nori@codegen@ir:endpoint()) -> binary().
generate_rq_query_hook(Endpoint) ->
Hook_name = <<"use"/utf8,
(nori@codegen@typescript@shared:to_pascal_case(
erlang:element(2, Endpoint)
))/binary>>,
Fn_name = nori@codegen@typescript@shared:to_camel_case(
erlang:element(2, Endpoint)
),
Return_type = get_response_type(erlang:element(10, Endpoint)),
Path_params = get_params_by_location(
erlang:element(8, Endpoint),
path_param
),
Query_params = get_params_by_location(
erlang:element(8, Endpoint),
query_param
),
Params = build_hook_params(Path_params, Query_params),
Call_args = build_call_args(Path_params, Query_params),
Query_key = build_query_key(Endpoint),
Summary_comment = case erlang:element(5, Endpoint) of
{some, S} ->
<<<<"/** "/utf8, S/binary>>/binary, " */\n"/utf8>>;
none ->
<<""/utf8>>
end,
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Summary_comment/binary,
"export function "/utf8>>/binary,
Hook_name/binary>>/binary,
"("/utf8>>/binary,
Params/binary>>/binary,
") {\n"/utf8>>/binary,
" return useQuery<"/utf8>>/binary,
Return_type/binary>>/binary,
">({\n"/utf8>>/binary,
" queryKey: "/utf8>>/binary,
Query_key/binary>>/binary,
",\n"/utf8>>/binary,
" queryFn: () => "/utf8>>/binary,
Fn_name/binary>>/binary,
"("/utf8>>/binary,
Call_args/binary>>/binary,
"),\n"/utf8>>/binary,
" });\n"/utf8>>/binary,
"}"/utf8>>.
-file("src/nori/codegen/templates.gleam", 560).
-spec generate_react_query_hook(nori@codegen@ir:endpoint()) -> binary().
generate_react_query_hook(Endpoint) ->
case erlang:element(3, Endpoint) of
get ->
generate_rq_query_hook(Endpoint);
_ ->
generate_rq_mutation_hook(Endpoint)
end.
-file("src/nori/codegen/templates.gleam", 972).
-spec is_mutation_method(nori@codegen@ir:http_method()) -> boolean().
is_mutation_method(Method) ->
case Method of
post ->
true;
put ->
true;
delete ->
true;
patch ->
true;
_ ->
false
end.
-file("src/nori/codegen/templates.gleam", 541).
-spec generate_rq_imports(nori@codegen@ir:codegen_i_r()) -> binary().
generate_rq_imports(Ir) ->
Has_queries = begin
_pipe = erlang:element(6, Ir),
gleam@list:any(_pipe, fun(E) -> erlang:element(3, E) =:= get end)
end,
Has_mutations = begin
_pipe@1 = erlang:element(6, Ir),
gleam@list:any(
_pipe@1,
fun(E@1) -> is_mutation_method(erlang:element(3, E@1)) end
)
end,
Imports = case {Has_queries, Has_mutations} of
{true, true} ->
<<"useQuery, useMutation"/utf8>>;
{true, false} ->
<<"useQuery"/utf8>>;
{false, true} ->
<<"useMutation"/utf8>>;
{false, false} ->
<<""/utf8>>
end,
case Imports of
<<""/utf8>> ->
<<""/utf8>>;
I ->
<<<<"import { "/utf8, I/binary>>/binary,
" } from \"@tanstack/react-query\";"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 479).
-spec ir_to_ts_react_query_context(nori@codegen@ir:codegen_i_r()) -> handles@ctx:value().
ir_to_ts_react_query_context(Ir) ->
Rq_imports = generate_rq_imports(Ir),
Type_imports = generate_type_imports(Ir),
Client_imports = generate_client_imports(Ir),
Tags = begin
_pipe = erlang:element(6, Ir),
_pipe@1 = gleam@list:flat_map(_pipe, fun(E) -> erlang:element(7, E) end),
gleam@list:unique(_pipe@1)
end,
Has_factories = Tags /= [],
Tag_count = erlang:length(Tags),
Key_factories = begin
_pipe@2 = Tags,
gleam@list:index_map(
_pipe@2,
fun(Tag, Idx) ->
Key = nori@codegen@typescript@shared:to_camel_case(Tag),
Factory_text = <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"export const "/utf8,
Key/binary>>/binary,
"Keys = {\n"/utf8>>/binary,
" all: [\""/utf8>>/binary,
Tag/binary>>/binary,
"\"] as const,\n"/utf8>>/binary,
" lists: () => [..."/utf8>>/binary,
Key/binary>>/binary,
"Keys.all, \"list\"] as const,\n"/utf8>>/binary,
" details: () => [..."/utf8>>/binary,
Key/binary>>/binary,
"Keys.all, \"detail\"] as const,\n"/utf8>>/binary,
" detail: (id: string | number) => [..."/utf8>>/binary,
Key/binary>>/binary,
"Keys.details(), id] as const,\n"/utf8>>/binary,
"};"/utf8>>,
{dict,
[{prop, <<"factory_text"/utf8>>, {str, Factory_text}},
{prop,
<<"is_last"/utf8>>,
{bool, Idx =:= (Tag_count - 1)}}]}
end
)
end,
Hook_count = erlang:length(erlang:element(6, Ir)),
Hooks = begin
_pipe@3 = erlang:element(6, Ir),
gleam@list:index_map(
_pipe@3,
fun(Ep, Idx@1) ->
Hook_text = generate_react_query_hook(Ep),
{dict,
[{prop, <<"hook_text"/utf8>>, {str, Hook_text}},
{prop,
<<"is_last"/utf8>>,
{bool, Idx@1 =:= (Hook_count - 1)}}]}
end
)
end,
{dict,
[{prop, <<"rq_imports"/utf8>>, {str, Rq_imports}},
{prop, <<"type_imports"/utf8>>, {str, Type_imports}},
{prop, <<"client_imports"/utf8>>, {str, Client_imports}},
{prop, <<"has_factories"/utf8>>, {bool, Has_factories}},
{prop, <<"key_factories"/utf8>>, {list, Key_factories}},
{prop, <<"hooks"/utf8>>, {list, Hooks}}]}.
-file("src/nori/codegen/templates.gleam", 664).
-spec generate_swr_imports(nori@codegen@ir:codegen_i_r()) -> binary().
generate_swr_imports(Ir) ->
Has_queries = begin
_pipe = erlang:element(6, Ir),
gleam@list:any(_pipe, fun(E) -> erlang:element(3, E) =:= get end)
end,
Has_mutations = begin
_pipe@1 = erlang:element(6, Ir),
gleam@list:any(
_pipe@1,
fun(E@1) -> is_mutation_method(erlang:element(3, E@1)) end
)
end,
case {Has_queries, Has_mutations} of
{true, true} ->
<<"import useSWR from \"swr\";\nimport useSWRMutation from \"swr/mutation\";"/utf8>>;
{true, false} ->
<<"import useSWR from \"swr\";"/utf8>>;
{false, true} ->
<<"import useSWRMutation from \"swr/mutation\";"/utf8>>;
{false, false} ->
<<""/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 640).
-spec ir_to_ts_swr_context(nori@codegen@ir:codegen_i_r()) -> handles@ctx:value().
ir_to_ts_swr_context(Ir) ->
Swr_imports = generate_swr_imports(Ir),
Type_imports = generate_type_imports(Ir),
Client_imports = generate_client_imports(Ir),
Hook_count = erlang:length(erlang:element(6, Ir)),
Hooks = begin
_pipe = erlang:element(6, Ir),
gleam@list:index_map(
_pipe,
fun(Ep, Idx) ->
Hook_text = generate_swr_hook(Ep),
{dict,
[{prop, <<"hook_text"/utf8>>, {str, Hook_text}},
{prop,
<<"is_last"/utf8>>,
{bool, Idx =:= (Hook_count - 1)}}]}
end
)
end,
{dict,
[{prop, <<"swr_imports"/utf8>>, {str, Swr_imports}},
{prop, <<"type_imports"/utf8>>, {str, Type_imports}},
{prop, <<"client_imports"/utf8>>, {str, Client_imports}},
{prop, <<"hooks"/utf8>>, {list, Hooks}}]}.
-file("src/nori/codegen/templates.gleam", 979).
-spec http_method_to_string(nori@codegen@ir:http_method()) -> binary().
http_method_to_string(Method) ->
case Method of
get ->
<<"GET"/utf8>>;
post ->
<<"POST"/utf8>>;
put ->
<<"PUT"/utf8>>;
delete ->
<<"DELETE"/utf8>>;
patch ->
<<"PATCH"/utf8>>;
head ->
<<"HEAD"/utf8>>;
options ->
<<"OPTIONS"/utf8>>
end.
-file("src/nori/codegen/templates.gleam", 311).
-spec generate_endpoint_function(nori@codegen@ir:endpoint(), boolean()) -> binary().
generate_endpoint_function(Endpoint, Cookie_auth) ->
Fn_name = nori@codegen@typescript@shared:to_camel_case(
erlang:element(2, Endpoint)
),
Method = http_method_to_string(erlang:element(3, Endpoint)),
Path_params = get_params_by_location(
erlang:element(8, Endpoint),
path_param
),
Query_params = get_params_by_location(
erlang:element(8, Endpoint),
query_param
),
Params = build_client_param_list(
Path_params,
Query_params,
erlang:element(9, Endpoint)
),
Return_type = get_response_type(erlang:element(10, Endpoint)),
Summary_comment = case erlang:element(5, Endpoint) of
{some, S} ->
<<<<"/** "/utf8, S/binary>>/binary, " */\n"/utf8>>;
none ->
<<""/utf8>>
end,
Deprecated_tag = case erlang:element(11, Endpoint) of
true ->
<<"/** @deprecated */\n"/utf8>>;
false ->
<<""/utf8>>
end,
Url_expr = build_url_expression(
erlang:element(4, Endpoint),
Path_params,
Query_params
),
Fetch_options = build_fetch_options(erlang:element(9, Endpoint)),
Response_handling = build_response_handling(Return_type),
Credentials_line = case Cookie_auth of
true ->
<<" credentials: _config.credentials ?? \"include\",\n"/utf8>>;
false ->
<<" credentials: _config.credentials,\n"/utf8>>
end,
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Deprecated_tag/binary,
Summary_comment/binary>>/binary,
"export async function "/utf8>>/binary,
Fn_name/binary>>/binary,
"("/utf8>>/binary,
Params/binary>>/binary,
"): Promise<"/utf8>>/binary,
Return_type/binary>>/binary,
"> {\n"/utf8>>/binary,
Url_expr/binary>>/binary,
" const response = await fetch(url, {\n"/utf8>>/binary,
" method: \""/utf8>>/binary,
Method/binary>>/binary,
"\",\n"/utf8>>/binary,
" headers: getHeaders(),\n"/utf8>>/binary,
Credentials_line/binary>>/binary,
Fetch_options/binary>>/binary,
" });\n"/utf8>>/binary,
"\n"/utf8>>/binary,
" if (!response.ok) {\n"/utf8>>/binary,
" let detail: string = response.statusText;\n"/utf8>>/binary,
" try {\n"/utf8>>/binary,
" const errBody = await response.clone().json();\n"/utf8>>/binary,
" if (errBody && typeof errBody.error === \"string\") detail = errBody.error;\n"/utf8>>/binary,
" } catch {}\n"/utf8>>/binary,
" throw new Error(`HTTP ${response.status}: ${detail}`);\n"/utf8>>/binary,
" }\n"/utf8>>/binary,
"\n"/utf8>>/binary,
Response_handling/binary>>/binary,
"}"/utf8>>.
-file("src/nori/codegen/templates.gleam", 245).
-spec ir_to_ts_client_context(nori@codegen@ir:codegen_i_r()) -> handles@ctx:value().
ir_to_ts_client_context(Ir) ->
Type_imports = generate_type_imports(Ir),
Cookie_auth = has_cookie_auth(Ir),
Config_type = <<<<<<<<<<"export interface ClientConfig {\n"/utf8,
" baseUrl: string;\n"/utf8>>/binary,
" headers?: Record<string, string>;\n"/utf8>>/binary,
" /** Override fetch credentials mode (defaults to 'include' when the spec uses cookie auth). */\n"/utf8>>/binary,
" credentials?: RequestCredentials;\n"/utf8>>/binary,
"}"/utf8>>,
Default_credentials = case Cookie_auth of
true ->
<<"\"include\""/utf8>>;
false ->
<<"undefined"/utf8>>
end,
Create_client = <<<<<<<<<<<<<<<<<<<<<<<<<<"let _config: ClientConfig = { baseUrl: \"\", credentials: "/utf8,
Default_credentials/binary>>/binary,
" };\n\n"/utf8>>/binary,
"export function configure(config: ClientConfig): void {\n"/utf8>>/binary,
" _config = { credentials: "/utf8>>/binary,
Default_credentials/binary>>/binary,
", ...config };\n"/utf8>>/binary,
"}\n\n"/utf8>>/binary,
"function getHeaders(): Record<string, string> {\n"/utf8>>/binary,
" return {\n"/utf8>>/binary,
" \"Content-Type\": \"application/json\",\n"/utf8>>/binary,
" ...(_config.headers ?? {}),\n"/utf8>>/binary,
" };\n"/utf8>>/binary,
"}"/utf8>>,
Fn_count = erlang:length(erlang:element(6, Ir)),
Functions = begin
_pipe = erlang:element(6, Ir),
gleam@list:index_map(
_pipe,
fun(Ep, Idx) ->
{dict,
[{prop,
<<"function_text"/utf8>>,
{str, generate_endpoint_function(Ep, Cookie_auth)}},
{prop,
<<"is_last"/utf8>>,
{bool, Idx =:= (Fn_count - 1)}}]}
end
)
end,
{dict,
[{prop, <<"type_imports"/utf8>>, {str, Type_imports}},
{prop, <<"config_type"/utf8>>, {str, Config_type}},
{prop, <<"create_client"/utf8>>, {str, Create_client}},
{prop, <<"functions"/utf8>>, {list, Functions}}]}.
-file("src/nori/codegen/templates.gleam", 991).
-spec opt_str(gleam@option:option(binary())) -> handles@ctx:value().
opt_str(Opt) ->
case Opt of
{some, S} ->
{str, S};
none ->
{str, <<""/utf8>>}
end.
-file("src/nori/codegen/templates.gleam", 217).
-spec field_to_ctx(nori@codegen@ir:field(), ts_config()) -> handles@ctx:value().
field_to_ctx(Field, Config) ->
Ts_type = nori@codegen@typescript@shared:type_ref_to_ts(
erlang:element(3, Field)
),
Is_optional = case erlang:element(4, Field) of
true ->
case erlang:element(3, Field) of
{optional, _} ->
true;
_ ->
false
end;
false ->
true
end,
{dict,
[{prop, <<"name"/utf8>>, {str, erlang:element(2, Field)}},
{prop, <<"ts_type"/utf8>>, {str, Ts_type}},
{prop, <<"optional"/utf8>>, {bool, Is_optional}},
{prop, <<"readonly"/utf8>>, {bool, erlang:element(4, Config)}},
{prop,
<<"has_field_description"/utf8>>,
{bool, gleam@option:is_some(erlang:element(5, Field))}},
{prop,
<<"field_description"/utf8>>,
opt_str(erlang:element(5, Field))}]}.
-file("src/nori/codegen/templates.gleam", 132).
-spec type_def_to_ctx(
nori@codegen@ir:type_def(),
ts_config(),
integer(),
integer()
) -> handles@ctx:value().
type_def_to_ctx(Td, Config, Index, Total) ->
Is_last = Index =:= (Total - 1),
Use_exports = erlang:element(2, Config),
Use_interfaces = erlang:element(3, Config),
case Td of
{record_type, Name, Fields, Description} ->
Field_values = begin
_pipe = Fields,
gleam@list:map(
_pipe,
fun(Field) -> field_to_ctx(Field, Config) end
)
end,
{dict,
[{prop, <<"is_record"/utf8>>, {bool, true}},
{prop, <<"is_enum"/utf8>>, {bool, false}},
{prop, <<"is_union"/utf8>>, {bool, false}},
{prop, <<"is_alias"/utf8>>, {bool, false}},
{prop, <<"name"/utf8>>, {str, Name}},
{prop,
<<"has_description"/utf8>>,
{bool, gleam@option:is_some(Description)}},
{prop, <<"description"/utf8>>, opt_str(Description)},
{prop, <<"use_exports"/utf8>>, {bool, Use_exports}},
{prop, <<"use_interfaces"/utf8>>, {bool, Use_interfaces}},
{prop, <<"fields"/utf8>>, {list, Field_values}},
{prop, <<"is_last"/utf8>>, {bool, Is_last}}]};
{enum_type, Name@1, Variants, Description@1} ->
Values = begin
_pipe@1 = Variants,
_pipe@2 = gleam@list:map(
_pipe@1,
fun(V) ->
<<<<"\""/utf8, (erlang:element(3, V))/binary>>/binary,
"\""/utf8>>
end
),
gleam@string:join(_pipe@2, <<" | "/utf8>>)
end,
{dict,
[{prop, <<"is_record"/utf8>>, {bool, false}},
{prop, <<"is_enum"/utf8>>, {bool, true}},
{prop, <<"is_union"/utf8>>, {bool, false}},
{prop, <<"is_alias"/utf8>>, {bool, false}},
{prop, <<"name"/utf8>>, {str, Name@1}},
{prop,
<<"has_description"/utf8>>,
{bool, gleam@option:is_some(Description@1)}},
{prop, <<"description"/utf8>>, opt_str(Description@1)},
{prop, <<"use_exports"/utf8>>, {bool, Use_exports}},
{prop, <<"enum_values"/utf8>>, {str, Values}},
{prop, <<"is_last"/utf8>>, {bool, Is_last}}]};
{union_type, Name@2, Members, _, Description@2} ->
Member_types = begin
_pipe@3 = Members,
_pipe@4 = gleam@list:map(
_pipe@3,
fun nori@codegen@typescript@shared:type_ref_to_ts/1
),
gleam@string:join(_pipe@4, <<" | "/utf8>>)
end,
{dict,
[{prop, <<"is_record"/utf8>>, {bool, false}},
{prop, <<"is_enum"/utf8>>, {bool, false}},
{prop, <<"is_union"/utf8>>, {bool, true}},
{prop, <<"is_alias"/utf8>>, {bool, false}},
{prop, <<"name"/utf8>>, {str, Name@2}},
{prop,
<<"has_description"/utf8>>,
{bool, gleam@option:is_some(Description@2)}},
{prop, <<"description"/utf8>>, opt_str(Description@2)},
{prop, <<"use_exports"/utf8>>, {bool, Use_exports}},
{prop, <<"union_members"/utf8>>, {str, Member_types}},
{prop, <<"is_last"/utf8>>, {bool, Is_last}}]};
{alias_type, Name@3, Target, Description@3} ->
{dict,
[{prop, <<"is_record"/utf8>>, {bool, false}},
{prop, <<"is_enum"/utf8>>, {bool, false}},
{prop, <<"is_union"/utf8>>, {bool, false}},
{prop, <<"is_alias"/utf8>>, {bool, true}},
{prop, <<"name"/utf8>>, {str, Name@3}},
{prop,
<<"has_description"/utf8>>,
{bool, gleam@option:is_some(Description@3)}},
{prop, <<"description"/utf8>>, opt_str(Description@3)},
{prop, <<"use_exports"/utf8>>, {bool, Use_exports}},
{prop,
<<"alias_target"/utf8>>,
{str,
nori@codegen@typescript@shared:type_ref_to_ts(
Target
)}},
{prop, <<"is_last"/utf8>>, {bool, Is_last}}]}
end.
-file("src/nori/codegen/templates.gleam", 121).
-spec ir_to_ts_types_context(nori@codegen@ir:codegen_i_r(), ts_config()) -> handles@ctx:value().
ir_to_ts_types_context(Ir, Config) ->
Type_count = erlang:length(erlang:element(5, Ir)),
Types = begin
_pipe = erlang:element(5, Ir),
gleam@list:index_map(
_pipe,
fun(Td, Idx) -> type_def_to_ctx(Td, Config, Idx, Type_count) end
)
end,
{dict, [{prop, <<"types"/utf8>>, {list, Types}}]}.
-file("src/nori/codegen/templates.gleam", 38).
?DOC(" Embedded default templates — used when .hbs files aren't found.\n").
-spec get_embedded_template(binary()) -> binary().
get_embedded_template(Name) ->
case Name of
<<"typescript_types"/utf8>> ->
<<"// Generated by nori - Do not edit manually
{{#each types}}{{#if is_record}}{{#if has_description}}/** {{description}} */
{{/if}}{{#if use_exports}}export {{/if}}{{#if use_interfaces}}interface {{name}} {
{{/if}}{{#unless use_interfaces}}type {{name}} = {
{{/unless}}{{#each fields}}{{#if has_field_description}} /** {{field_description}} */
{{/if}} {{#if readonly}}readonly {{/if}}{{name}}{{#if optional}}?{{/if}}: {{ts_type}};
{{/each}}}{{/if}}{{#if is_enum}}{{#if has_description}}/** {{description}} */
{{/if}}{{#if use_exports}}export {{/if}}type {{name}} = {{enum_values}};{{/if}}{{#if is_union}}{{#if has_description}}/** {{description}} */
{{/if}}{{#if use_exports}}export {{/if}}type {{name}} = {{union_members}};{{/if}}{{#if is_alias}}{{#if has_description}}/** {{description}} */
{{/if}}{{#if use_exports}}export {{/if}}type {{name}} = {{alias_target}};{{/if}}{{#unless is_last}}
{{/unless}}{{/each}}"/utf8>>;
<<"typescript_client"/utf8>> ->
<<"// Generated by nori - Do not edit manually
{{type_imports}}
{{config_type}}
{{create_client}}
{{#each functions}}{{function_text}}{{#unless is_last}}
{{/unless}}{{/each}}"/utf8>>;
<<"typescript_react_query"/utf8>> ->
<<"// Generated by nori - Do not edit manually
{{rq_imports}}
{{type_imports}}
{{client_imports}}
{{#if has_factories}}{{#each key_factories}}{{factory_text}}{{#unless is_last}}
{{/unless}}{{/each}}
{{/if}}{{#each hooks}}{{hook_text}}{{#unless is_last}}
{{/unless}}{{/each}}"/utf8>>;
<<"typescript_swr"/utf8>> ->
<<"// Generated by nori - Do not edit manually
{{swr_imports}}
{{type_imports}}
{{client_imports}}
{{#each hooks}}{{hook_text}}{{#unless is_last}}
{{/unless}}{{/each}}"/utf8>>;
_ ->
<<"// Unknown template: "/utf8, Name/binary>>
end.
-file("src/nori/codegen/templates.gleam", 29).
?DOC(" Load a template from file, or fall back to the embedded default.\n").
-spec load_template(binary(), binary()) -> binary().
load_template(Template_dir, Name) ->
Path = <<<<<<Template_dir/binary, "/"/utf8>>/binary, Name/binary>>/binary,
".hbs"/utf8>>,
case simplifile:read(Path) of
{ok, Content} ->
Content;
{error, _} ->
get_embedded_template(Name)
end.