Current section
Files
Jump to
Current section
Files
src/atproto_codegen@emit.erl
-module(atproto_codegen@emit).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/atproto_codegen/emit.gleam").
-export([emit_lexicon/2]).
-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(
" Emit Gleam source (types + `gleam/json` encoders + `gleam/dynamic/decode`\n"
" decoders) from lexicon defs, plus the fixed `internal` helper module.\n"
).
-file("src/atproto_codegen/emit.gleam", 21).
-spec escape(binary()) -> binary().
escape(Value) ->
_pipe = Value,
_pipe@1 = gleam@string:replace(_pipe, <<"\\"/utf8>>, <<"\\\\"/utf8>>),
gleam@string:replace(_pipe@1, <<"\""/utf8>>, <<"\\\""/utf8>>).
-file("src/atproto_codegen/emit.gleam", 27).
-spec type_uses_helper(atproto_codegen@lexicon:field_type()) -> boolean().
type_uses_helper(Ft) ->
case Ft of
t_cid_link ->
true;
t_bytes ->
true;
t_unknown ->
true;
{t_array, Inner} ->
type_uses_helper(Inner);
_ ->
false
end.
-file("src/atproto_codegen/emit.gleam", 35).
-spec type_uses_blob(atproto_codegen@lexicon:field_type()) -> boolean().
type_uses_blob(Ft) ->
case Ft of
t_blob ->
true;
{t_array, Inner} ->
type_uses_blob(Inner);
_ ->
false
end.
-file("src/atproto_codegen/emit.gleam", 43).
-spec type_uses_unknown(atproto_codegen@lexicon:field_type()) -> boolean().
type_uses_unknown(Ft) ->
case Ft of
t_unknown ->
true;
{t_array, Inner} ->
type_uses_unknown(Inner);
_ ->
false
end.
-file("src/atproto_codegen/emit.gleam", 51).
-spec gleam_type(
atproto_codegen@config:config(),
binary(),
atproto_codegen@lexicon:field_type()
) -> binary().
gleam_type(Cfg, Current, Ft) ->
case Ft of
t_string ->
<<"String"/utf8>>;
t_int ->
<<"Int"/utf8>>;
t_bool ->
<<"Bool"/utf8>>;
t_number ->
<<"Float"/utf8>>;
{t_ref, Ref} ->
R = atproto_codegen@naming:parse_ref(Current, Ref),
<<(atproto_codegen@naming:qualifier(
erlang:element(5, Cfg),
Current,
erlang:element(2, R)
))/binary,
(atproto_codegen@naming:ref_type_name(erlang:element(5, Cfg), R))/binary>>;
{t_array, Inner} ->
<<<<"List("/utf8, (gleam_type(Cfg, Current, Inner))/binary>>/binary,
")"/utf8>>;
t_cid_link ->
<<"String"/utf8>>;
t_bytes ->
<<"BitArray"/utf8>>;
t_blob ->
<<"blob.Blob"/utf8>>;
t_unknown ->
<<"dynamic.Dynamic"/utf8>>;
{t_unsupported, Kind} ->
<<"Dynamic_"/utf8, Kind/binary>>
end.
-file("src/atproto_codegen/emit.gleam", 71).
-spec encoder_expr(
atproto_codegen@config:config(),
binary(),
atproto_codegen@lexicon:field_type()
) -> binary().
encoder_expr(Cfg, Current, Ft) ->
case Ft of
t_string ->
<<"json.string"/utf8>>;
t_int ->
<<"json.int"/utf8>>;
t_bool ->
<<"json.bool"/utf8>>;
t_number ->
<<"json.float"/utf8>>;
{t_ref, Ref} ->
R = atproto_codegen@naming:parse_ref(Current, Ref),
<<<<(atproto_codegen@naming:qualifier(
erlang:element(5, Cfg),
Current,
erlang:element(2, R)
))/binary,
"encode_"/utf8>>/binary,
(justin:snake_case(
atproto_codegen@naming:ref_type_name(
erlang:element(5, Cfg),
R
)
))/binary>>;
{t_array, Inner} ->
<<<<"fn(items) { json.array(items, "/utf8,
(encoder_expr(Cfg, Current, Inner))/binary>>/binary,
") }"/utf8>>;
t_cid_link ->
<<"internal.encode_cid_link"/utf8>>;
t_bytes ->
<<"internal.encode_bytes"/utf8>>;
t_blob ->
<<"blob.encode_blob"/utf8>>;
t_unknown ->
<<"internal.dynamic_to_json"/utf8>>;
{t_unsupported, _} ->
<<"json.string"/utf8>>
end.
-file("src/atproto_codegen/emit.gleam", 95).
-spec decoder_expr(
atproto_codegen@config:config(),
binary(),
atproto_codegen@lexicon:field_type()
) -> binary().
decoder_expr(Cfg, Current, Ft) ->
case Ft of
t_string ->
<<"decode.string"/utf8>>;
t_int ->
<<"decode.int"/utf8>>;
t_bool ->
<<"decode.bool"/utf8>>;
t_number ->
<<"decode.float"/utf8>>;
{t_ref, Ref} ->
R = atproto_codegen@naming:parse_ref(Current, Ref),
<<<<(atproto_codegen@naming:qualifier(
erlang:element(5, Cfg),
Current,
erlang:element(2, R)
))/binary,
(justin:snake_case(
atproto_codegen@naming:ref_type_name(
erlang:element(5, Cfg),
R
)
))/binary>>/binary,
"_decoder()"/utf8>>;
{t_array, Inner} ->
<<<<"decode.list("/utf8,
(decoder_expr(Cfg, Current, Inner))/binary>>/binary,
")"/utf8>>;
t_cid_link ->
<<"internal.cid_link_decoder()"/utf8>>;
t_bytes ->
<<"internal.bytes_decoder()"/utf8>>;
t_blob ->
<<"blob.blob_decoder()"/utf8>>;
t_unknown ->
<<"decode.dynamic"/utf8>>;
{t_unsupported, _} ->
<<"decode.string"/utf8>>
end.
-file("src/atproto_codegen/emit.gleam", 186).
-spec ref_nsids(atproto_codegen@lexicon:field_type()) -> list(binary()).
ref_nsids(Ft) ->
case Ft of
{t_ref, Ref} ->
R = atproto_codegen@naming:parse_ref(<<""/utf8>>, Ref),
case erlang:element(2, R) of
<<""/utf8>> ->
[];
Nsid ->
[Nsid]
end;
{t_array, Inner} ->
ref_nsids(Inner);
_ ->
[]
end.
-file("src/atproto_codegen/emit.gleam", 178).
-spec def_properties(atproto_codegen@lexicon:def()) -> list(atproto_codegen@lexicon:property()).
def_properties(Def) ->
case Def of
{record, _, Props} ->
Props;
{object, _, _, Props@1} ->
Props@1;
_ ->
[]
end.
-file("src/atproto_codegen/emit.gleam", 134).
-spec emit_header(
atproto_codegen@config:config(),
binary(),
list(atproto_codegen@lexicon:def())
) -> binary().
emit_header(Cfg, Nsid, Defs) ->
Props = gleam@list:flat_map(Defs, fun def_properties/1),
Needs_option = gleam@list:any(Props, fun(P) -> not erlang:element(4, P) end),
Uses_helper = gleam@list:any(
Props,
fun(P@1) -> type_uses_helper(erlang:element(3, P@1)) end
),
Uses_unknown = gleam@list:any(
Props,
fun(P@2) -> type_uses_unknown(erlang:element(3, P@2)) end
),
Uses_blob = gleam@list:any(
Props,
fun(P@3) -> type_uses_blob(erlang:element(3, P@3)) end
),
Externals = begin
_pipe = Props,
_pipe@1 = gleam@list:flat_map(
_pipe,
fun(P@4) -> ref_nsids(erlang:element(3, P@4)) end
),
_pipe@2 = gleam@list:filter(_pipe@1, fun(N) -> N /= Nsid end),
_pipe@3 = gleam@list:unique(_pipe@2),
gleam@list:sort(_pipe@3, fun gleam@string:compare/2)
end,
Base = [<<"import gleam/dynamic/decode"/utf8>>,
<<"import gleam/json"/utf8>>,
<<"import gleam/list"/utf8>>],
Blob = case Uses_blob of
true ->
[<<"import atproto/blob"/utf8>>];
false ->
[]
end,
Dyn = case Uses_unknown of
true ->
[<<"import gleam/dynamic"/utf8>>];
false ->
[]
end,
Opt = case Needs_option of
true ->
[<<"import gleam/option.{type Option}"/utf8>>];
false ->
[]
end,
Internal = case Needs_option orelse Uses_helper of
true ->
[<<<<"import "/utf8, (erlang:element(4, Cfg))/binary>>/binary,
"/internal"/utf8>>];
false ->
[]
end,
Ext = gleam@list:map(
Externals,
fun(N@1) ->
<<<<<<<<<<"import "/utf8, (erlang:element(4, Cfg))/binary>>/binary,
"/"/utf8>>/binary,
(atproto_codegen@naming:module_subpath(
erlang:element(5, Cfg),
N@1
))/binary>>/binary,
" as "/utf8>>/binary,
(atproto_codegen@naming:module_alias(
erlang:element(5, Cfg),
N@1
))/binary>>
end
),
<<(gleam@string:join(
lists:append([Blob, Base, Dyn, Opt, Internal, Ext]),
<<"\n"/utf8>>
))/binary,
"\n"/utf8>>.
-file("src/atproto_codegen/emit.gleam", 296).
-spec emit_decoder(
atproto_codegen@config:config(),
binary(),
binary(),
list(atproto_codegen@lexicon:property())
) -> binary().
emit_decoder(Cfg, Nsid, Name, Props) ->
Uses = gleam@list:map(
Props,
fun(P) ->
Var = atproto_codegen@naming:field_name(erlang:element(2, P)),
case erlang:element(4, P) of
true ->
<<<<<<<<<<<<" use "/utf8, Var/binary>>/binary,
" <- decode.field(\""/utf8>>/binary,
(escape(erlang:element(2, P)))/binary>>/binary,
"\", "/utf8>>/binary,
(decoder_expr(Cfg, Nsid, erlang:element(3, P)))/binary>>/binary,
")"/utf8>>;
false ->
<<<<<<<<<<<<" use "/utf8, Var/binary>>/binary,
" <- decode.optional_field(\""/utf8>>/binary,
(escape(erlang:element(2, P)))/binary>>/binary,
"\", option.None, decode.optional("/utf8>>/binary,
(decoder_expr(Cfg, Nsid, erlang:element(3, P)))/binary>>/binary,
"))"/utf8>>
end
end
),
Constructor = case Props of
[] ->
<<<<" decode.success("/utf8, Name/binary>>/binary, ")"/utf8>>;
_ ->
<<<<<<<<" decode.success("/utf8, Name/binary>>/binary, "("/utf8>>/binary,
(gleam@string:join(
gleam@list:map(
Props,
fun(P@1) ->
<<(atproto_codegen@naming:field_name(
erlang:element(2, P@1)
))/binary,
":"/utf8>>
end
),
<<", "/utf8>>
))/binary>>/binary,
"))"/utf8>>
end,
<<<<<<<<<<<<<<<<"pub fn "/utf8, (justin:snake_case(Name))/binary>>/binary,
"_decoder() -> decode.Decoder("/utf8>>/binary,
Name/binary>>/binary,
") {\n"/utf8>>/binary,
(gleam@string:join(Uses, <<"\n"/utf8>>))/binary>>/binary,
"\n"/utf8>>/binary,
Constructor/binary>>/binary,
"\n}"/utf8>>.
-file("src/atproto_codegen/emit.gleam", 250).
-spec emit_encoder(
atproto_codegen@config:config(),
binary(),
binary(),
list(atproto_codegen@lexicon:property()),
boolean()
) -> binary().
emit_encoder(Cfg, Nsid, Name, Props, Is_record) ->
{Required, Optional} = gleam@list:partition(
Props,
fun(P) -> erlang:element(4, P) end
),
Required_entries = gleam@list:map(
Required,
fun(P@1) ->
<<<<<<<<<<<<"#(\""/utf8, (escape(erlang:element(2, P@1)))/binary>>/binary,
"\", "/utf8>>/binary,
(encoder_expr(Cfg, Nsid, erlang:element(3, P@1)))/binary>>/binary,
"(value."/utf8>>/binary,
(atproto_codegen@naming:field_name(erlang:element(2, P@1)))/binary>>/binary,
"))"/utf8>>
end
),
Type_entry = case Is_record of
true ->
[<<<<"#(\"$type\", json.string(\""/utf8, (escape(Nsid))/binary>>/binary,
"\"))"/utf8>>];
false ->
[]
end,
Inline = <<<<"["/utf8,
(gleam@string:join(
lists:append([Type_entry, Required_entries]),
<<", "/utf8>>
))/binary>>/binary,
"]"/utf8>>,
Optional_groups = gleam@list:map(
Optional,
fun(P@2) ->
<<<<<<<<<<<<"internal.opt(\""/utf8,
(escape(erlang:element(2, P@2)))/binary>>/binary,
"\", value."/utf8>>/binary,
(atproto_codegen@naming:field_name(
erlang:element(2, P@2)
))/binary>>/binary,
", "/utf8>>/binary,
(encoder_expr(Cfg, Nsid, erlang:element(3, P@2)))/binary>>/binary,
")"/utf8>>
end
),
Groups = gleam@string:join([Inline | Optional_groups], <<",\n "/utf8>>),
<<<<<<<<<<<<"pub fn encode_"/utf8, (justin:snake_case(Name))/binary>>/binary,
"(value: "/utf8>>/binary,
Name/binary>>/binary,
") -> json.Json {\n json.object(list.flatten([\n "/utf8>>/binary,
Groups/binary>>/binary,
",\n ]))\n}"/utf8>>.
-file("src/atproto_codegen/emit.gleam", 221).
-spec emit_type(
atproto_codegen@config:config(),
binary(),
binary(),
list(atproto_codegen@lexicon:property())
) -> binary().
emit_type(Cfg, Nsid, Name, Props) ->
case Props of
[] ->
<<<<<<<<"pub type "/utf8, Name/binary>>/binary, " {\n "/utf8>>/binary,
Name/binary>>/binary,
"\n}"/utf8>>;
_ ->
Fields = gleam@list:map(
Props,
fun(P) ->
T = gleam_type(Cfg, Nsid, erlang:element(3, P)),
T@1 = case erlang:element(4, P) of
true ->
T;
false ->
<<<<"Option("/utf8, T/binary>>/binary, ")"/utf8>>
end,
<<<<<<<<" "/utf8,
(atproto_codegen@naming:field_name(
erlang:element(2, P)
))/binary>>/binary,
": "/utf8>>/binary,
T@1/binary>>/binary,
","/utf8>>
end
),
<<<<<<<<<<<<"pub type "/utf8, Name/binary>>/binary, " {\n "/utf8>>/binary,
Name/binary>>/binary,
"(\n"/utf8>>/binary,
(gleam@string:join(Fields, <<"\n"/utf8>>))/binary>>/binary,
"\n )\n}"/utf8>>
end.
-file("src/atproto_codegen/emit.gleam", 200).
-spec emit_def(
atproto_codegen@config:config(),
binary(),
atproto_codegen@lexicon:def()
) -> binary().
emit_def(Cfg, Nsid, Def) ->
Name = atproto_codegen@naming:def_type_name(erlang:element(5, Cfg), Def),
Props = def_properties(Def),
Is_record = case Def of
{record, _, _} ->
true;
_ ->
false
end,
gleam@string:join(lists:append([case Is_record of
true ->
[<<<<"pub const collection = \""/utf8,
(escape(Nsid))/binary>>/binary,
"\""/utf8>>];
false ->
[]
end, [emit_type(Cfg, Nsid, Name, Props)], [emit_encoder(
Cfg,
Nsid,
Name,
Props,
Is_record
)], [emit_decoder(Cfg, Nsid, Name, Props)]]), <<"\n\n"/utf8>>).
-file("src/atproto_codegen/emit.gleam", 116).
-spec emit_lexicon(
atproto_codegen@config:config(),
atproto_codegen@lexicon:lexicon()
) -> gleam@option:option(binary()).
emit_lexicon(Cfg, Lex) ->
Emittable = gleam@list:filter(erlang:element(3, Lex), fun(D) -> case D of
{record, _, _} ->
true;
{object, _, _, _} ->
true;
_ ->
false
end end),
case Emittable of
[] ->
none;
Defs ->
Bodies = gleam@list:map(
Defs,
fun(_capture) ->
emit_def(Cfg, erlang:element(2, Lex), _capture)
end
),
Header = emit_header(Cfg, erlang:element(2, Lex), Defs),
{some,
<<<<<<<<"//// Generated by codegen from lexicons/. Do not edit by hand.\n\n"/utf8,
Header/binary>>/binary,
"\n"/utf8>>/binary,
(gleam@string:join(Bodies, <<"\n\n"/utf8>>))/binary>>/binary,
"\n"/utf8>>}
end.