Packages

Generate Gleam types, JSON codecs, and a typed XRPC client from atproto lexicon files.

Current section

Files

Jump to
atproto_codegen src atproto_codegen@emit.erl
Raw

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 from lexicon defs: module header, def dispatch, and the\n"
" per-def pieces from `emit/def` + `emit/union`.\n"
).
-file("src/atproto_codegen/emit.gleam", 102).
-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", 95).
-spec def_uses_flatten(atproto_codegen@lexicon:def()) -> boolean().
def_uses_flatten(Def) ->
Props = def_properties(Def),
Optional = gleam@list:count(Props, fun(P) -> not erlang:element(4, P) end),
Required = erlang:length(Props) - Optional,
(Optional >= 1) andalso ((Required >= 1) orelse (Optional >= 2)).
-file("src/atproto_codegen/emit.gleam", 119).
-spec ref_nsid(binary()) -> list(binary()).
ref_nsid(Ref) ->
R = atproto_codegen@naming:parse_ref(<<""/utf8>>, Ref),
case erlang:element(2, R) of
<<""/utf8>> ->
[];
Nsid ->
[Nsid]
end.
-file("src/atproto_codegen/emit.gleam", 110).
-spec ref_nsids(atproto_codegen@lexicon:field_type()) -> list(binary()).
ref_nsids(Ft) ->
case Ft of
{t_ref, Ref} ->
ref_nsid(Ref);
{t_union, Refs} ->
gleam@list:flat_map(Refs, fun ref_nsid/1);
{t_array, Inner} ->
ref_nsids(Inner);
_ ->
[]
end.
-file("src/atproto_codegen/emit.gleam", 40).
-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) ->
atproto_codegen@emit@exprs:type_uses_helper(erlang:element(3, P@1))
end
),
Uses_unknown = gleam@list:any(
Props,
fun(P@2) ->
atproto_codegen@emit@exprs:type_uses_unknown(erlang:element(3, P@2))
end
),
Uses_blob = gleam@list:any(
Props,
fun(P@3) ->
atproto_codegen@emit@exprs: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,
Uses_list = gleam@list:any(Defs, fun def_uses_flatten/1),
Base = case Uses_list of
true ->
[<<"import gleam/dynamic/decode"/utf8>>,
<<"import gleam/json"/utf8>>,
<<"import gleam/list"/utf8>>];
false ->
[<<"import gleam/dynamic/decode"/utf8>>,
<<"import gleam/json"/utf8>>]
end,
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) ->
Subpath = atproto_codegen@naming:module_subpath(
erlang:element(5, Cfg),
N@1
),
Alias = atproto_codegen@naming:module_alias(
erlang:element(5, Cfg),
N@1
),
Default_name = begin
_pipe@4 = gleam@string:split(Subpath, <<"/"/utf8>>),
_pipe@5 = gleam@list:last(_pipe@4),
gleam@result:unwrap(_pipe@5, Subpath)
end,
Rename = case Alias =:= Default_name of
true ->
<<""/utf8>>;
false ->
<<" as "/utf8, Alias/binary>>
end,
<<<<<<<<"import "/utf8, (erlang:element(4, Cfg))/binary>>/binary,
"/"/utf8>>/binary,
Subpath/binary>>/binary,
Rename/binary>>
end
),
<<(gleam@string:join(
lists:append([Blob, Base, Dyn, Opt, Internal, Ext]),
<<"\n"/utf8>>
))/binary,
"\n"/utf8>>.
-file("src/atproto_codegen/emit.gleam", 127).
-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,
Unions = begin
_pipe = Props,
gleam@list:filter_map(
_pipe,
fun(P) ->
case atproto_codegen@emit@exprs:union_of(erlang:element(3, P)) of
{some, Refs} ->
{ok,
atproto_codegen@emit@union:emit_union(
Cfg,
Nsid,
atproto_codegen@emit@exprs:union_type_name(
Cfg,
Def,
P
),
Refs
)};
none ->
{error, nil}
end
end
)
end,
gleam@string:join(lists:append([case Is_record of
true ->
[<<<<"pub const collection = \""/utf8,
(atproto_codegen@emit@exprs:escape(Nsid))/binary>>/binary,
"\""/utf8>>];
false ->
[]
end, [atproto_codegen@emit@def:emit_type(
Cfg,
Nsid,
Def,
Name,
Props
)], [atproto_codegen@emit@def:emit_fields(
Cfg,
Nsid,
Def,
Name,
Props
)], [atproto_codegen@emit@def:emit_encoder(
Nsid,
Name,
Is_record
)], [atproto_codegen@emit@def:emit_decoder(
Cfg,
Nsid,
Def,
Name,
Props
)], Unions]), <<"\n\n"/utf8>>).
-file("src/atproto_codegen/emit.gleam", 22).
-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.