Packages
caffeine_lang
3.0.0
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
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
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_lang@frontend@generator.erl
-module(caffeine_lang@frontend@generator).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/frontend/generator.gleam").
-export([generate_blueprints_json/1, generate_expects_json/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/frontend/generator.gleam", 48).
?DOC(" Builds a map of extendable name to extendable for quick lookup.\n").
-spec build_extendable_map(list(caffeine_lang@frontend@ast:extendable())) -> gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable()).
build_extendable_map(Extendables) ->
_pipe = Extendables,
_pipe@1 = gleam@list:map(_pipe, fun(E) -> {erlang:element(2, E), E} end),
maps:from_list(_pipe@1).
-file("src/caffeine_lang/frontend/generator.gleam", 160).
?DOC(
" Removes duplicate field names, keeping the last occurrence (allows overrides).\n"
" Returns fields sorted by name for consistent JSON output.\n"
).
-spec dedupe_fields(list(caffeine_lang@frontend@ast:field())) -> list(caffeine_lang@frontend@ast:field()).
dedupe_fields(Fields) ->
_pipe = Fields,
_pipe@1 = gleam@list:fold(
_pipe,
maps:new(),
fun(Acc, Field) ->
gleam@dict:insert(Acc, erlang:element(2, Field), Field)
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:map(_pipe@3, fun(Pair) -> erlang:element(2, Pair) end).
-file("src/caffeine_lang/frontend/generator.gleam", 101).
?DOC(
" Merges extended fields into a blueprint item's requires and provides.\n"
" Order: extended extendables left-to-right, then item's own fields (can override).\n"
).
-spec merge_blueprint_extends(
caffeine_lang@frontend@ast:blueprint_item(),
gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable())
) -> {caffeine_lang@frontend@ast:struct(), caffeine_lang@frontend@ast:struct()}.
merge_blueprint_extends(Item, Extendables) ->
Requires_fields = begin
_pipe = erlang:element(3, Item),
_pipe@1 = gleam@list:flat_map(
_pipe,
fun(Name) -> case gleam_stdlib:map_get(Extendables, Name) of
{ok, Ext} ->
case erlang:element(3, Ext) of
extendable_requires ->
erlang:element(2, erlang:element(4, Ext));
extendable_provides ->
[]
end;
{error, _} ->
[]
end end
),
_pipe@2 = lists:append(
_pipe@1,
erlang:element(2, erlang:element(4, Item))
),
dedupe_fields(_pipe@2)
end,
Provides_fields = begin
_pipe@3 = erlang:element(3, Item),
_pipe@4 = gleam@list:flat_map(
_pipe@3,
fun(Name@1) -> case gleam_stdlib:map_get(Extendables, Name@1) of
{ok, Ext@1} ->
case erlang:element(3, Ext@1) of
extendable_provides ->
erlang:element(2, erlang:element(4, Ext@1));
extendable_requires ->
[]
end;
{error, _} ->
[]
end end
),
_pipe@5 = lists:append(
_pipe@4,
erlang:element(2, erlang:element(5, Item))
),
dedupe_fields(_pipe@5)
end,
{{struct, Requires_fields}, {struct, Provides_fields}}.
-file("src/caffeine_lang/frontend/generator.gleam", 140).
?DOC(
" Merges extended fields into an expect item's provides.\n"
" Order: extended extendables left-to-right, then item's own fields (can override).\n"
).
-spec merge_expect_extends(
caffeine_lang@frontend@ast:expect_item(),
gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable())
) -> caffeine_lang@frontend@ast:struct().
merge_expect_extends(Item, Extendables) ->
Provides_fields = begin
_pipe = erlang:element(3, Item),
_pipe@1 = gleam@list:flat_map(
_pipe,
fun(Name) -> case gleam_stdlib:map_get(Extendables, Name) of
{ok, Ext} ->
erlang:element(2, erlang:element(4, Ext));
{error, _} ->
[]
end end
),
_pipe@2 = lists:append(
_pipe@1,
erlang:element(2, erlang:element(4, Item))
),
dedupe_fields(_pipe@2)
end,
{struct, Provides_fields}.
-file("src/caffeine_lang/frontend/generator.gleam", 171).
?DOC(" Converts a struct with type values to a JSON params object.\n").
-spec struct_to_params_json(caffeine_lang@frontend@ast:struct()) -> gleam@json:json().
struct_to_params_json(S) ->
_pipe = erlang:element(2, S),
_pipe@1 = gleam@list:sort(
_pipe,
fun(A, B) ->
gleam@string:compare(erlang:element(2, A), erlang:element(2, B))
end
),
_pipe@2 = gleam@list:map(
_pipe@1,
fun(Field) ->
Type_string = case erlang:element(3, Field) of
{type_value, T} ->
caffeine_lang@common@accepted_types:accepted_type_to_string(
T
);
{literal_value, _} ->
<<""/utf8>>
end,
{erlang:element(2, Field), gleam@json:string(Type_string)}
end
),
gleam@json:object(_pipe@2).
-file("src/caffeine_lang/frontend/generator.gleam", 232).
-spec transform_template_vars_loop(binary(), binary()) -> binary().
transform_template_vars_loop(Remaining, Acc) ->
case gleam@string:split_once(Remaining, <<"$"/utf8>>) of
{ok, {Before, After}} ->
case gleam_stdlib:string_starts_with(After, <<"$"/utf8>>) of
true ->
transform_template_vars_loop(
gleam@string:drop_start(After, 1),
<<<<Acc/binary, Before/binary>>/binary, "$$"/utf8>>
);
false ->
case gleam@string:split_once(After, <<"$"/utf8>>) of
{ok, {Var_content, Rest}} ->
Transformed = gleam@string:replace(
Var_content,
<<".not"/utf8>>,
<<":not"/utf8>>
),
transform_template_vars_loop(
Rest,
<<<<<<<<Acc/binary, Before/binary>>/binary,
"$$"/utf8>>/binary,
Transformed/binary>>/binary,
"$$"/utf8>>
);
{error, nil} ->
<<<<<<Acc/binary, Before/binary>>/binary, "$"/utf8>>/binary,
After/binary>>
end
end;
{error, nil} ->
<<Acc/binary, Remaining/binary>>
end.
-file("src/caffeine_lang/frontend/generator.gleam", 228).
?DOC(
" Transforms template variables from $var->attr$ to $$var->attr$$ format.\n"
" Also handles $var->attr.not$ to $$var->attr:not$$ format.\n"
).
-spec transform_template_vars(binary()) -> binary().
transform_template_vars(S) ->
transform_template_vars_loop(S, <<""/utf8>>).
-file("src/caffeine_lang/frontend/generator.gleam", 213).
?DOC(" Converts a literal struct's fields to a JSON object.\n").
-spec literal_struct_to_json(list(caffeine_lang@frontend@ast:field())) -> gleam@json:json().
literal_struct_to_json(Fields) ->
_pipe = Fields,
_pipe@1 = gleam@list:sort(
_pipe,
fun(A, B) ->
gleam@string:compare(erlang:element(2, A), erlang:element(2, B))
end
),
_pipe@2 = gleam@list:map(
_pipe@1,
fun(Field) ->
Json_value = case erlang:element(3, Field) of
{literal_value, Lit} ->
literal_to_json(Lit);
{type_value, _} ->
gleam@json:null()
end,
{erlang:element(2, Field), Json_value}
end
),
gleam@json:object(_pipe@2).
-file("src/caffeine_lang/frontend/generator.gleam", 199).
?DOC(" Converts a literal to a JSON value.\n").
-spec literal_to_json(caffeine_lang@frontend@ast:literal()) -> gleam@json:json().
literal_to_json(Lit) ->
case Lit of
{literal_string, S} ->
gleam@json:string(transform_template_vars(S));
{literal_integer, I} ->
gleam@json:int(I);
{literal_float, F} ->
gleam@json:float(F);
literal_true ->
gleam@json:bool(true);
literal_false ->
gleam@json:bool(false);
{literal_list, Elements} ->
gleam@json:array(Elements, fun(E) -> literal_to_json(E) end);
{literal_struct, Fields} ->
literal_struct_to_json(Fields)
end.
-file("src/caffeine_lang/frontend/generator.gleam", 185).
?DOC(" Converts a struct with literal values to a JSON inputs object.\n").
-spec struct_to_inputs_json(caffeine_lang@frontend@ast:struct()) -> gleam@json:json().
struct_to_inputs_json(S) ->
_pipe = erlang:element(2, S),
_pipe@1 = gleam@list:sort(
_pipe,
fun(A, B) ->
gleam@string:compare(erlang:element(2, A), erlang:element(2, B))
end
),
_pipe@2 = gleam@list:map(
_pipe@1,
fun(Field) ->
Json_value = case erlang:element(3, Field) of
{literal_value, Lit} ->
literal_to_json(Lit);
{type_value, _} ->
gleam@json:null()
end,
{erlang:element(2, Field), Json_value}
end
),
gleam@json:object(_pipe@2).
-file("src/caffeine_lang/frontend/generator.gleam", 57).
?DOC(" Generates JSON for a single blueprint item.\n").
-spec generate_blueprint_item_json(
caffeine_lang@frontend@ast:blueprint_item(),
list(binary()),
gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable())
) -> gleam@json:json().
generate_blueprint_item_json(Item, Artifacts, Extendables) ->
{Merged_requires, Merged_provides} = merge_blueprint_extends(
Item,
Extendables
),
Params = struct_to_params_json(Merged_requires),
Inputs = struct_to_inputs_json(Merged_provides),
gleam@json:object(
[{<<"name"/utf8>>, gleam@json:string(erlang:element(2, Item))},
{<<"artifact_refs"/utf8>>,
gleam@json:array(Artifacts, fun gleam@json:string/1)},
{<<"params"/utf8>>, Params},
{<<"inputs"/utf8>>, Inputs}]
).
-file("src/caffeine_lang/frontend/generator.gleam", 15).
?DOC(false).
-spec generate_blueprints_json(caffeine_lang@frontend@ast:blueprints_file()) -> gleam@json:json().
generate_blueprints_json(File) ->
Extendables = build_extendable_map(erlang:element(2, File)),
Blueprints = begin
_pipe = erlang:element(3, File),
gleam@list:flat_map(
_pipe,
fun(Block) -> _pipe@1 = erlang:element(3, Block),
gleam@list:map(
_pipe@1,
fun(Item) ->
generate_blueprint_item_json(
Item,
erlang:element(2, Block),
Extendables
)
end
) end
)
end,
gleam@json:object(
[{<<"blueprints"/utf8>>, gleam@json:array(Blueprints, fun(X) -> X end)}]
).
-file("src/caffeine_lang/frontend/generator.gleam", 81).
?DOC(" Generates JSON for a single expect item.\n").
-spec generate_expect_item_json(
caffeine_lang@frontend@ast:expect_item(),
binary(),
gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable())
) -> gleam@json:json().
generate_expect_item_json(Item, Blueprint, Extendables) ->
Merged_provides = merge_expect_extends(Item, Extendables),
Inputs = struct_to_inputs_json(Merged_provides),
gleam@json:object(
[{<<"name"/utf8>>, gleam@json:string(erlang:element(2, Item))},
{<<"blueprint_ref"/utf8>>, gleam@json:string(Blueprint)},
{<<"inputs"/utf8>>, Inputs}]
).
-file("src/caffeine_lang/frontend/generator.gleam", 32).
?DOC(false).
-spec generate_expects_json(caffeine_lang@frontend@ast:expects_file()) -> gleam@json:json().
generate_expects_json(File) ->
Extendables = build_extendable_map(erlang:element(2, File)),
Expectations = begin
_pipe = erlang:element(3, File),
gleam@list:flat_map(
_pipe,
fun(Block) -> _pipe@1 = erlang:element(3, Block),
gleam@list:map(
_pipe@1,
fun(Item) ->
generate_expect_item_json(
Item,
erlang:element(2, Block),
Extendables
)
end
) end
)
end,
gleam@json:object(
[{<<"expectations"/utf8>>,
gleam@json:array(Expectations, fun(X) -> X end)}]
).