Current section

Files

Jump to
caffeine_lang src caffeine_lang@codegen@dependency_graph.erl
Raw

src/caffeine_lang@codegen@dependency_graph.erl

-module(caffeine_lang@codegen@dependency_graph).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/codegen/dependency_graph.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/caffeine_lang/codegen/dependency_graph.gleam", 119).
-spec is_id_char(binary()) -> boolean().
is_id_char(G) ->
case G of
<<"_"/utf8>> ->
true;
_ ->
case gleam@string:to_utf_codepoints(G) of
[Cp] ->
Code = gleam_stdlib:identity(Cp),
(((Code >= 65) andalso (Code =< 90)) orelse ((Code >= 97)
andalso (Code =< 122)))
orelse ((Code >= 48) andalso (Code =< 57));
_ ->
false
end
end.
-file("src/caffeine_lang/codegen/dependency_graph.gleam", 102).
?DOC(" Strips all non-alphanumeric characters (except underscores) for Mermaid-safe node IDs.\n").
-spec sanitize_id(binary()) -> binary().
sanitize_id(Path) ->
_pipe = Path,
_pipe@1 = gleam@string:to_graphemes(_pipe),
_pipe@2 = gleam@list:map(_pipe@1, fun(G) -> case G of
<<"."/utf8>> ->
<<"_"/utf8>>;
<<" "/utf8>> ->
<<"_"/utf8>>;
<<"-"/utf8>> ->
<<"_"/utf8>>;
_ ->
case is_id_char(G) of
true ->
G;
false ->
<<""/utf8>>
end
end end),
erlang:list_to_binary(_pipe@2).
-file("src/caffeine_lang/codegen/dependency_graph.gleam", 57).
?DOC(" Generates Mermaid edge declarations for hard and soft dependencies.\n").
-spec build_edges(
list(caffeine_lang@linker@ir:intermediate_representation(caffeine_lang@linker@ir:resolved()))
) -> list(binary()).
build_edges(Irs) ->
_pipe = Irs,
gleam@list:flat_map(
_pipe,
fun(Ir) ->
Source_id = sanitize_id(
caffeine_lang@linker@ir:ir_to_identifier(Ir)
),
case erlang:element(8, erlang:element(5, Ir)) of
none ->
[];
{some, Relations} ->
Hard_edges = begin
_pipe@1 = gleam_stdlib:map_get(Relations, hard),
_pipe@2 = gleam@result:unwrap(_pipe@1, []),
gleam@list:map(
_pipe@2,
fun(Target) ->
<<<<<<" "/utf8, Source_id/binary>>/binary,
" -->|hard| "/utf8>>/binary,
(sanitize_id(Target))/binary>>
end
)
end,
Soft_edges = begin
_pipe@3 = gleam_stdlib:map_get(Relations, soft),
_pipe@4 = gleam@result:unwrap(_pipe@3, []),
gleam@list:map(
_pipe@4,
fun(Target@1) ->
<<<<<<" "/utf8, Source_id/binary>>/binary,
" -.->|soft| "/utf8>>/binary,
(sanitize_id(Target@1))/binary>>
end
)
end,
lists:append(Hard_edges, Soft_edges)
end
end
).
-file("src/caffeine_lang/codegen/dependency_graph.gleam", 88).
?DOC(
" Escapes characters that have special meaning in Mermaid labels.\n"
" Uses numeric HTML entity codes (e.g. #91; for [) which are broadly compatible.\n"
).
-spec escape_label(binary()) -> binary().
escape_label(Text) ->
_pipe = Text,
_pipe@1 = gleam@string:replace(_pipe, <<"\""/utf8>>, <<"#34;"/utf8>>),
_pipe@2 = gleam@string:replace(_pipe@1, <<"["/utf8>>, <<"#91;"/utf8>>),
_pipe@3 = gleam@string:replace(_pipe@2, <<"]"/utf8>>, <<"#93;"/utf8>>),
_pipe@4 = gleam@string:replace(_pipe@3, <<"("/utf8>>, <<"#40;"/utf8>>),
_pipe@5 = gleam@string:replace(_pipe@4, <<")"/utf8>>, <<"#41;"/utf8>>),
_pipe@6 = gleam@string:replace(_pipe@5, <<"{"/utf8>>, <<"#123;"/utf8>>),
_pipe@7 = gleam@string:replace(_pipe@6, <<"}"/utf8>>, <<"#125;"/utf8>>),
_pipe@8 = gleam@string:replace(_pipe@7, <<"<"/utf8>>, <<"#60;"/utf8>>),
gleam@string:replace(_pipe@8, <<">"/utf8>>, <<"#62;"/utf8>>).
-file("src/caffeine_lang/codegen/dependency_graph.gleam", 49).
?DOC(" Generates a single Mermaid node declaration with just the expectation name.\n").
-spec build_node(
caffeine_lang@linker@ir:intermediate_representation(caffeine_lang@linker@ir:resolved())
) -> binary().
build_node(Ir) ->
Path = caffeine_lang@linker@ir:ir_to_identifier(Ir),
Id = sanitize_id(Path),
Safe_name = escape_label(
erlang:element(2, erlang:element(2, erlang:element(2, Ir)))
),
<<<<<<<<" "/utf8, Id/binary>>/binary, "[\""/utf8>>/binary,
Safe_name/binary>>/binary,
"\"]"/utf8>>.
-file("src/caffeine_lang/codegen/dependency_graph.gleam", 44).
?DOC(" Builds the service grouping key from IR metadata.\n").
-spec service_key(
caffeine_lang@linker@ir:intermediate_representation(caffeine_lang@linker@ir:resolved())
) -> binary().
service_key(Ir) ->
erlang:element(2, erlang:element(4, erlang:element(2, Ir))).
-file("src/caffeine_lang/codegen/dependency_graph.gleam", 23).
?DOC(" Groups IRs by service and generates Mermaid subgraph blocks.\n").
-spec build_subgraphs(
list(caffeine_lang@linker@ir:intermediate_representation(caffeine_lang@linker@ir:resolved()))
) -> list(binary()).
build_subgraphs(Irs) ->
_pipe = Irs,
_pipe@1 = gleam@list:group(_pipe, fun(Ir) -> service_key(Ir) end),
_pipe@2 = maps:to_list(_pipe@1),
_pipe@3 = gleam@list:sort(
_pipe@2,
fun(A, B) ->
gleam@string:compare(erlang:element(1, A), erlang:element(1, B))
end
),
gleam@list:flat_map(
_pipe@3,
fun(Group) ->
{Service, Group_irs} = Group,
Header = <<<<<<<<" subgraph "/utf8,
(sanitize_id(Service))/binary>>/binary,
"[\""/utf8>>/binary,
(escape_label(Service))/binary>>/binary,
"\"]"/utf8>>,
Nodes = gleam@list:map(Group_irs, fun build_node/1),
lists:append([[Header], Nodes, [<<" end"/utf8>>]])
end
).
-file("src/caffeine_lang/codegen/dependency_graph.gleam", 13).
?DOC(
" Generates a Mermaid flowchart string from dependency relations in IRs.\n"
" Nodes are grouped into subgraphs by service.\n"
).
-spec generate(
list(caffeine_lang@linker@ir:intermediate_representation(caffeine_lang@linker@ir:resolved()))
) -> binary().
generate(Irs) ->
Subgraphs = build_subgraphs(Irs),
Edges = build_edges(Irs),
_pipe = [[<<"graph TD"/utf8>>], Subgraphs, Edges],
_pipe@1 = lists:append(_pipe),
gleam@string:join(_pipe@1, <<"\n"/utf8>>).