Current section

Files

Jump to
caffeine_lang src caffeine_lang@linker@ir_builder.erl
Raw

src/caffeine_lang@linker@ir_builder.erl

-module(caffeine_lang@linker@ir_builder).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/linker/ir_builder.gleam").
-export([reserved_labels_from_artifacts/1, build_all/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.
-file("src/caffeine_lang/linker/ir_builder.gleam", 26).
?DOC(false).
-spec reserved_labels_from_artifacts(
list(caffeine_lang@linker@artifacts:artifact())
) -> gleam@set:set(binary()).
reserved_labels_from_artifacts(Artifacts) ->
_pipe = Artifacts,
_pipe@1 = gleam@list:flat_map(
_pipe,
fun(Artifact) -> maps:keys(erlang:element(4, Artifact)) end
),
_pipe@2 = gleam@set:from_list(_pipe@1),
gleam@set:delete(_pipe@2, <<"vendor"/utf8>>).
-file("src/caffeine_lang/linker/ir_builder.gleam", 97).
?DOC(
" Resolves the vendor from value tuples at IR construction time.\n"
" SLO artifacts require a vendor; dependency-only artifacts get None.\n"
).
-spec resolve_vendor_from_values(
list(caffeine_lang@helpers:value_tuple()),
list(caffeine_lang@linker@artifacts:artifact_type()),
binary()
) -> {ok, gleam@option:option(caffeine_lang@analysis@vendor:vendor())} |
{error, caffeine_lang@errors:compilation_error()}.
resolve_vendor_from_values(Value_tuples, Artifact_refs, Identifier) ->
Has_slo = gleam@list:contains(Artifact_refs, s_l_o),
gleam@bool:guard(
not Has_slo,
{ok, none},
fun() ->
Vendor_value = begin
_pipe = Value_tuples,
gleam@list:find(
_pipe,
fun(Vt) -> erlang:element(2, Vt) =:= <<"vendor"/utf8>> end
)
end,
case Vendor_value of
{error, nil} ->
{error,
{linker_vendor_resolution_error,
<<<<"expectation '"/utf8, Identifier/binary>>/binary,
"' - missing 'vendor' field"/utf8>>,
caffeine_lang@errors:empty_context()}};
{ok, Vt@1} ->
case caffeine_lang@value:extract_string(
erlang:element(4, Vt@1)
) of
{error, _} ->
{error,
{linker_vendor_resolution_error,
<<<<"expectation '"/utf8,
Identifier/binary>>/binary,
"' - 'vendor' field is not a string"/utf8>>,
caffeine_lang@errors:empty_context()}};
{ok, Vendor_string} ->
case caffeine_lang@analysis@vendor:resolve_vendor(
Vendor_string
) of
{ok, V} ->
{ok, {some, V}};
{error, _} ->
{error,
{linker_vendor_resolution_error,
<<<<<<<<"expectation '"/utf8,
Identifier/binary>>/binary,
"' - unknown vendor '"/utf8>>/binary,
Vendor_string/binary>>/binary,
"'"/utf8>>,
caffeine_lang@errors:empty_context()}}
end
end
end
end
).
-file("src/caffeine_lang/linker/ir_builder.gleam", 155).
?DOC(" Build value tuples from provided inputs.\n").
-spec build_provided_value_tuples(
gleam@dict:dict(binary(), caffeine_lang@value:value()),
gleam@dict:dict(binary(), caffeine_lang@types:accepted_types())
) -> list(caffeine_lang@helpers:value_tuple()).
build_provided_value_tuples(Merged_inputs, Params) ->
_pipe = Merged_inputs,
_pipe@1 = maps:to_list(_pipe),
gleam@list:filter_map(
_pipe@1,
fun(Pair) ->
{Label, Val} = Pair,
case gleam_stdlib:map_get(Params, Label) of
{ok, Typ} ->
{ok, {value_tuple, Label, Typ, Val}};
{error, nil} ->
{error, nil}
end
end
).
-file("src/caffeine_lang/linker/ir_builder.gleam", 172).
?DOC(
" Build value tuples for Optional/Defaulted params that weren't provided.\n"
" These need to be in value_tuples so the templatizer can resolve them.\n"
).
-spec build_unprovided_optional_value_tuples(
gleam@dict:dict(binary(), caffeine_lang@value:value()),
gleam@dict:dict(binary(), caffeine_lang@types:accepted_types())
) -> list(caffeine_lang@helpers:value_tuple()).
build_unprovided_optional_value_tuples(Merged_inputs, Params) ->
_pipe = Params,
_pipe@1 = maps:to_list(_pipe),
gleam@list:filter_map(
_pipe@1,
fun(Param) ->
{Label, Typ} = Param,
gleam@bool:guard(
gleam@dict:has_key(Merged_inputs, Label),
{error, nil},
fun() ->
case caffeine_lang@types:is_optional_or_defaulted(Typ) of
true ->
{ok, {value_tuple, Label, Typ, nil_value}};
false ->
{error, nil}
end
end
)
end
).
-file("src/caffeine_lang/linker/ir_builder.gleam", 145).
?DOC(
" Build value tuples from merged inputs and params.\n"
" Includes both provided inputs and unprovided Optional/Defaulted params.\n"
).
-spec build_value_tuples(
gleam@dict:dict(binary(), caffeine_lang@value:value()),
gleam@dict:dict(binary(), caffeine_lang@types:accepted_types())
) -> list(caffeine_lang@helpers:value_tuple()).
build_value_tuples(Merged_inputs, Params) ->
Provided = build_provided_value_tuples(Merged_inputs, Params),
Unprovided = build_unprovided_optional_value_tuples(Merged_inputs, Params),
lists:append(Provided, Unprovided).
-file("src/caffeine_lang/linker/ir_builder.gleam", 220).
?DOC(
" Resolves a value tuple to a list of strings for use as tags.\n"
" Primitives and refinements produce a single-element list.\n"
" Lists are exploded into multiple string values.\n"
" Dicts and type alias refs are unsupported.\n"
" Optional(None) produces an empty list (filtered out).\n"
" Defaulted(None) produces the default value.\n"
).
-spec resolve_values_for_tag(
caffeine_lang@types:accepted_types(),
caffeine_lang@value:value()
) -> {ok, list(binary())} | {error, nil}.
resolve_values_for_tag(Typ, Val) ->
case Typ of
{primitive_type, _} ->
{ok, [caffeine_lang@value:to_string(Val)]};
{refinement_type, Refinement} ->
case Refinement of
{one_of, Inner, _} ->
resolve_values_for_tag(Inner, Val);
{inclusive_range, Inner@1, _, _} ->
resolve_values_for_tag(Inner@1, Val)
end;
{collection_type, {list, Inner@2}} ->
case Val of
{list_value, Items} ->
_pipe = Items,
_pipe@2 = gleam@list:try_map(
_pipe,
fun(Item) ->
_pipe@1 = resolve_values_for_tag(Inner@2, Item),
gleam@result:map(
_pipe@1,
fun(Strings) -> Strings end
)
end
),
gleam@result:map(_pipe@2, fun lists:append/1);
_ ->
{error, nil}
end;
{collection_type, {dict, _, _}} ->
{error, nil};
{record_type, _} ->
{error, nil};
{modifier_type, {optional, Inner@3}} ->
case Val of
nil_value ->
{ok, []};
_ ->
resolve_values_for_tag(Inner@3, Val)
end;
{modifier_type, {defaulted, Inner@4, Default}} ->
case Val of
nil_value ->
{ok, [Default]};
_ ->
resolve_values_for_tag(Inner@4, Val)
end
end.
-file("src/caffeine_lang/linker/ir_builder.gleam", 195).
?DOC(
" Extract misc metadata from value tuples.\n"
" Filters out reserved labels (derived from artifact params) and unsupported types.\n"
" Each key maps to a list of string values (primitives become single-element\n"
" lists, collection lists are exploded, nulls are excluded).\n"
).
-spec extract_misc_metadata(
list(caffeine_lang@helpers:value_tuple()),
gleam@set:set(binary())
) -> gleam@dict:dict(binary(), list(binary())).
extract_misc_metadata(Value_tuples, Reserved_labels) ->
_pipe = Value_tuples,
_pipe@1 = gleam@list:filter_map(
_pipe,
fun(Value_tuple) ->
gleam@bool:guard(
gleam@set:contains(
Reserved_labels,
erlang:element(2, Value_tuple)
),
{error, nil},
fun() ->
case resolve_values_for_tag(
erlang:element(3, Value_tuple),
erlang:element(4, Value_tuple)
) of
{ok, []} ->
{error, nil};
{ok, Values} ->
{ok, {erlang:element(2, Value_tuple), Values}};
{error, _} ->
{error, nil}
end
end
)
end
),
maps:from_list(_pipe@1).
-file("src/caffeine_lang/linker/ir_builder.gleam", 300).
?DOC(" Extract SLO-specific fields from value tuples.\n").
-spec build_slo_fields(list(caffeine_lang@helpers:value_tuple())) -> caffeine_lang@linker@ir:slo_fields().
build_slo_fields(Value_tuples) ->
Threshold = caffeine_lang@helpers:extract_threshold(Value_tuples),
Indicators = caffeine_lang@helpers:extract_indicators(Value_tuples),
Window_in_days = caffeine_lang@helpers:extract_window_in_days(Value_tuples),
Evaluation = begin
_pipe = caffeine_lang@helpers:extract_value(
Value_tuples,
<<"evaluation"/utf8>>,
fun caffeine_lang@value:extract_string/1
),
gleam@option:from_result(_pipe)
end,
Tags = caffeine_lang@helpers:extract_tags(Value_tuples),
Runbook = begin
_pipe@1 = caffeine_lang@helpers:extract_value(
Value_tuples,
<<"runbook"/utf8>>,
fun(V) -> case V of
nil_value ->
{ok, none};
{string_value, S} ->
{ok, {some, S}};
_ ->
{error, nil}
end end
),
gleam@result:unwrap(_pipe@1, none)
end,
{slo_fields,
Threshold,
Indicators,
Window_in_days,
Evaluation,
Tags,
Runbook}.
-file("src/caffeine_lang/linker/ir_builder.gleam", 331).
?DOC(" Extract dependency-specific fields from value tuples.\n").
-spec build_dependency_fields(list(caffeine_lang@helpers:value_tuple())) -> caffeine_lang@linker@ir:dependency_fields().
build_dependency_fields(Value_tuples) ->
{dependency_fields,
caffeine_lang@helpers:extract_relations(Value_tuples),
caffeine_lang@helpers:extract_tags(Value_tuples)}.
-file("src/caffeine_lang/linker/ir_builder.gleam", 262).
?DOC(" Build structured artifact data from artifact refs and value tuples.\n").
-spec build_artifact_data(
list(caffeine_lang@linker@artifacts:artifact_type()),
list(caffeine_lang@helpers:value_tuple())
) -> caffeine_lang@linker@ir:artifact_data().
build_artifact_data(Artifact_refs, Value_tuples) ->
Fields = begin
_pipe = Artifact_refs,
_pipe@1 = gleam@list:map(_pipe, fun(Ref) -> case Ref of
s_l_o ->
{s_l_o,
{slo_artifact_fields,
build_slo_fields(Value_tuples)}};
dependency_relations ->
{dependency_relations,
{dependency_artifact_fields,
build_dependency_fields(Value_tuples)}}
end end),
maps:from_list(_pipe@1)
end,
Fields@1 = case gleam@dict:is_empty(Fields) of
true ->
maps:from_list(
[{s_l_o, {slo_artifact_fields, build_slo_fields(Value_tuples)}}]
);
false ->
Fields
end,
{artifact_data, Fields@1}.
-file("src/caffeine_lang/linker/ir_builder.gleam", 49).
?DOC(" Build intermediate representations from validated expectations for a single file.\n").
-spec build(
list({caffeine_lang@linker@expectations:expectation(),
caffeine_lang@linker@blueprints:blueprint()}),
binary(),
gleam@set:set(binary())
) -> {ok, list(caffeine_lang@linker@ir:intermediate_representation())} |
{error, caffeine_lang@errors:compilation_error()}.
build(Expectations_blueprint_collection, File_path, Reserved_labels) ->
{Org, Team, Service} = caffeine_lang@helpers:extract_path_prefix(File_path),
_pipe = Expectations_blueprint_collection,
gleam@list:try_map(
_pipe,
fun(Expectation_and_blueprint_pair) ->
{Expectation, Blueprint} = Expectation_and_blueprint_pair,
Merged_inputs = maps:merge(
erlang:element(5, Blueprint),
erlang:element(4, Expectation)
),
Value_tuples = build_value_tuples(
Merged_inputs,
erlang:element(4, Blueprint)
),
Misc_metadata = extract_misc_metadata(Value_tuples, Reserved_labels),
Unique_name = <<<<<<<<Org/binary, "_"/utf8>>/binary,
Service/binary>>/binary,
"_"/utf8>>/binary,
(erlang:element(2, Expectation))/binary>>,
Artifact_data = build_artifact_data(
erlang:element(3, Blueprint),
Value_tuples
),
gleam@result:'try'(
resolve_vendor_from_values(
Value_tuples,
erlang:element(3, Blueprint),
<<<<<<<<<<<<Org/binary, "."/utf8>>/binary, Team/binary>>/binary,
"."/utf8>>/binary,
Service/binary>>/binary,
"."/utf8>>/binary,
(erlang:element(2, Expectation))/binary>>
),
fun(Resolved_vendor) ->
{ok,
{intermediate_representation,
{intermediate_representation_meta_data,
erlang:element(2, Expectation),
Org,
Service,
erlang:element(2, Blueprint),
Team,
Misc_metadata},
Unique_name,
erlang:element(3, Blueprint),
Value_tuples,
Artifact_data,
Resolved_vendor}}
end
)
end
).
-file("src/caffeine_lang/linker/ir_builder.gleam", 35).
?DOC(false).
-spec build_all(
list({list({caffeine_lang@linker@expectations:expectation(),
caffeine_lang@linker@blueprints:blueprint()}),
binary()}),
gleam@set:set(binary())
) -> {ok, list(caffeine_lang@linker@ir:intermediate_representation())} |
{error, caffeine_lang@errors:compilation_error()}.
build_all(Expectations_with_paths, Reserved_labels) ->
_pipe = Expectations_with_paths,
_pipe@1 = gleam@list:map(
_pipe,
fun(Pair) ->
{Expectations_blueprint_collection, File_path} = Pair,
build(Expectations_blueprint_collection, File_path, Reserved_labels)
end
),
_pipe@2 = caffeine_lang@errors:from_results(_pipe@1),
gleam@result:map(_pipe@2, fun lists:append/1).