-module(aws@endpoints).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/aws/endpoints.gleam").
-export([params_from/2, parse_rule_set/1, resolve/2]).
-export_type([endpoint/0, resolve_error/0, value/0, rule_set/0, parameter/0, param_type/0, rule/0, endpoint_spec/0, condition/0, expr/0, template_part/0, partition/0]).
-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(
" Smithy endpoint rule set evaluator.\n"
"\n"
" Implements the runtime side of the Smithy rules engine: parses a\n"
" `endpoint-rule-set.json` document, then walks it against a set of\n"
" parameter values and produces a concrete endpoint URL.\n"
"\n"
" Supported features:\n"
"\n"
" - Rule types: `endpoint`, `error`, `tree`\n"
" - Parameters: `String`, `Boolean`, with `default` and `required`\n"
" - Templates: `{Name}` and `{Var#field}` (and nested `{Var#a#b}`)\n"
" - Built-in functions: `isSet`, `not`, `booleanEquals`, `stringEquals`,\n"
" `getAttr`, `substring`, `uriEncode`, `parseURL`, `isValidHostLabel`,\n"
" `aws.partition`, `aws.parseArn`, `aws.isVirtualHostableS3Bucket`\n"
" - Common partition data hardcoded (`aws`, `aws-cn`, `aws-us-gov`).\n"
" For a richer table, vendor `partitions.json` and replace\n"
" `partition_for/1`.\n"
"\n"
" Not implemented (rare; flagged at evaluation time as `Unsupported`):\n"
"\n"
" - `StringArray` parameter type (used by a few new services)\n"
"\n"
" Codegen at milestone 7 will use this evaluator at compile time to emit\n"
" per-service endpoint resolvers; the runtime fallback path here keeps\n"
" hand-written services working before any code is generated.\n"
).
-type endpoint() :: {endpoint,
binary(),
gleam@dict:dict(binary(), list(binary()))}.
-type resolve_error() :: {rule_error, binary()} |
no_match |
{invalid_rule_set, binary()} |
{unsupported, binary()} |
{missing_parameter, binary()} |
{required_parameter_missing, binary()}.
-type value() :: {string_val, binary()} |
{bool_val, boolean()} |
{record_val, gleam@dict:dict(binary(), value())} |
{list_val, list(value())} |
empty_val.
-type rule_set() :: {rule_set,
gleam@dict:dict(binary(), parameter()),
list(rule())}.
-type parameter() :: {parameter,
param_type(),
boolean(),
gleam@option:option(value()),
gleam@option:option(binary())}.
-type param_type() :: string_type | boolean_type.
-type rule() :: {endpoint_rule, list(condition()), endpoint_spec()} |
{error_rule, list(condition()), expr()} |
{tree_rule, list(condition()), list(rule())}.
-type endpoint_spec() :: {endpoint_spec,
expr(),
gleam@dict:dict(binary(), list(expr()))}.
-type condition() :: {condition, expr(), gleam@option:option(binary())}.
-type expr() :: {ref, binary()} |
{template_expr, list(template_part())} |
{bool_lit, boolean()} |
{int_lit, integer()} |
{fn_call, binary(), list(expr())}.
-type template_part() :: {static, binary()} | {interp, list(binary())}.
-type partition() :: aws_commercial |
aws_cn |
aws_us_gov |
aws_eusc |
aws_iso |
aws_iso_b |
aws_iso_e |
aws_iso_f.
-file("src/aws/endpoints.gleam", 77).
?DOC(
" Convenience constructor: build a `Params` map from string and boolean\n"
" pairs. The most common shape (Region + UseFips + UseDualStack).\n"
).
-spec params_from(list({binary(), binary()}), list({binary(), boolean()})) -> gleam@dict:dict(binary(), value()).
params_from(Strings, Bools) ->
S_dict = gleam@list:fold(
Strings,
maps:new(),
fun(Acc, Pair) ->
gleam@dict:insert(
Acc,
erlang:element(1, Pair),
{string_val, erlang:element(2, Pair)}
)
end
),
gleam@list:fold(
Bools,
S_dict,
fun(Acc@1, Pair@1) ->
gleam@dict:insert(
Acc@1,
erlang:element(1, Pair@1),
{bool_val, erlang:element(2, Pair@1)}
)
end
).
-file("src/aws/endpoints.gleam", 302).
-spec describe_decode_error(gleam@json:decode_error()) -> binary().
describe_decode_error(Err) ->
case Err of
{unexpected_byte, B} ->
<<"unexpected byte: "/utf8, B/binary>>;
unexpected_end_of_input ->
<<"unexpected end of input"/utf8>>;
{unexpected_sequence, _} ->
<<"unexpected sequence in JSON"/utf8>>;
{unable_to_decode, _} ->
<<"JSON did not match rule set schema"/utf8>>
end.
-file("src/aws/endpoints.gleam", 215).
-spec error_rule_failsafe() -> rule().
error_rule_failsafe() ->
{error_rule, [], {template_expr, [{static, <<"unknown rule"/utf8>>}]}}.
-file("src/aws/endpoints.gleam", 321).
-spec do_parse_template(binary(), binary(), list(template_part())) -> list(template_part()).
do_parse_template(Remaining, Static_buf, Acc) ->
case gleam@string:split_once(Remaining, <<"{"/utf8>>) of
{error, _} ->
lists:reverse(
[{static, <<Static_buf/binary, Remaining/binary>>} | Acc]
);
{ok, {Before_brace, Rest_with_brace}} ->
case gleam@string:split_once(Rest_with_brace, <<"}"/utf8>>) of
{error, _} ->
lists:reverse(
[{static, <<Static_buf/binary, Remaining/binary>>} |
Acc]
);
{ok, {Interp_body, After_close}} ->
New_static = <<Static_buf/binary, Before_brace/binary>>,
Acc@1 = case New_static of
<<""/utf8>> ->
Acc;
_ ->
[{static, New_static} | Acc]
end,
Path = gleam@string:split(Interp_body, <<"#"/utf8>>),
Acc@2 = [{interp, Path} | Acc@1],
do_parse_template(After_close, <<""/utf8>>, Acc@2)
end
end.
-file("src/aws/endpoints.gleam", 317).
?DOC(
" Split a raw template string into static + interpolation segments.\n"
" `{Region}` becomes `Interp([\"Region\"])`. `{var#field#sub}` becomes\n"
" `Interp([\"var\", \"field\", \"sub\"])`. Literal `{{` and `}}` are NOT supported\n"
" — none of the AWS rule sets in scope use escaped braces.\n"
).
-spec parse_template(binary()) -> list(template_part()).
parse_template(Text) ->
do_parse_template(Text, <<""/utf8>>, []).
-file("src/aws/endpoints.gleam", 271).
-spec string_expr_decoder() -> gleam@dynamic@decode:decoder(expr()).
string_expr_decoder() ->
gleam@dynamic@decode:map(
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(S) -> {template_expr, parse_template(S)} end
).
-file("src/aws/endpoints.gleam", 252).
-spec int_decoder() -> gleam@dynamic@decode:decoder(expr()).
int_decoder() ->
gleam@dynamic@decode:map(
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun(Field@0) -> {int_lit, Field@0} end
).
-file("src/aws/endpoints.gleam", 261).
-spec bool_decoder() -> gleam@dynamic@decode:decoder(expr()).
bool_decoder() ->
gleam@dynamic@decode:map(
{decoder, fun gleam@dynamic@decode:decode_bool/1},
fun(Field@0) -> {bool_lit, Field@0} end
).
-file("src/aws/endpoints.gleam", 256).
-spec ref_decoder() -> gleam@dynamic@decode:decoder(expr()).
ref_decoder() ->
gleam@dynamic@decode:field(
<<"ref"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Name) -> gleam@dynamic@decode:success({ref, Name}) end
).
-file("src/aws/endpoints.gleam", 265).
-spec fn_call_decoder() -> gleam@dynamic@decode:decoder(expr()).
fn_call_decoder() ->
gleam@dynamic@decode:field(
<<"fn"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Fn_name) ->
gleam@dynamic@decode:field(
<<"argv"/utf8>>,
gleam@dynamic@decode:list(expr_decoder()),
fun(Argv) ->
gleam@dynamic@decode:success({fn_call, Fn_name, Argv})
end
)
end
).
-file("src/aws/endpoints.gleam", 243).
?DOC(
" Decoder for an `Expr` — i.e. anything that can appear in an `argv` slot\n"
" of a function call or as the value of an endpoint property. Smithy rules\n"
" allow several shapes here, so we use `one_of` to try each in turn.\n"
).
-spec expr_decoder() -> gleam@dynamic@decode:decoder(expr()).
expr_decoder() ->
gleam@dynamic@decode:one_of(
ref_decoder(),
[bool_decoder(),
int_decoder(),
fn_call_decoder(),
string_expr_decoder()]
).
-file("src/aws/endpoints.gleam", 226).
-spec condition_decoder() -> gleam@dynamic@decode:decoder(condition()).
condition_decoder() ->
gleam@dynamic@decode:field(
<<"fn"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Fn_name) ->
gleam@dynamic@decode:field(
<<"argv"/utf8>>,
gleam@dynamic@decode:list(expr_decoder()),
fun(Argv) ->
gleam@dynamic@decode:then(
gleam@dynamic@decode:optionally_at(
[<<"assign"/utf8>>],
none,
gleam@dynamic@decode:map(
{decoder,
fun gleam@dynamic@decode:decode_string/1},
fun(Field@0) -> {some, Field@0} end
)
),
fun(Assign) ->
gleam@dynamic@decode:success(
{condition, {fn_call, Fn_name, Argv}, Assign}
)
end
)
end
)
end
).
-file("src/aws/endpoints.gleam", 222).
-spec conditions_decoder() -> gleam@dynamic@decode:decoder(list(condition())).
conditions_decoder() ->
gleam@dynamic@decode:list(condition_decoder()).
-file("src/aws/endpoints.gleam", 290).
-spec error_rule_decoder() -> gleam@dynamic@decode:decoder(rule()).
error_rule_decoder() ->
gleam@dynamic@decode:field(
<<"conditions"/utf8>>,
conditions_decoder(),
fun(Conditions) ->
gleam@dynamic@decode:field(
<<"error"/utf8>>,
expr_decoder(),
fun(Message) ->
gleam@dynamic@decode:success(
{error_rule, Conditions, Message}
)
end
)
end
).
-file("src/aws/endpoints.gleam", 276).
?DOC(" Endpoint rule fields: `endpoint = { url, properties, headers }`.\n").
-spec endpoint_rule_decoder() -> gleam@dynamic@decode:decoder(rule()).
endpoint_rule_decoder() ->
gleam@dynamic@decode:field(
<<"conditions"/utf8>>,
conditions_decoder(),
fun(Conditions) ->
gleam@dynamic@decode:subfield(
[<<"endpoint"/utf8>>, <<"url"/utf8>>],
expr_decoder(),
fun(Url) ->
gleam@dynamic@decode:then(
gleam@dynamic@decode:optionally_at(
[<<"endpoint"/utf8>>, <<"headers"/utf8>>],
maps:new(),
gleam@dynamic@decode:dict(
{decoder,
fun gleam@dynamic@decode:decode_string/1},
gleam@dynamic@decode:list(expr_decoder())
)
),
fun(Headers) ->
gleam@dynamic@decode:success(
{endpoint_rule,
Conditions,
{endpoint_spec, Url, Headers}}
)
end
)
end
)
end
).
-file("src/aws/endpoints.gleam", 296).
-spec tree_rule_decoder() -> gleam@dynamic@decode:decoder(rule()).
tree_rule_decoder() ->
gleam@dynamic@decode:field(
<<"conditions"/utf8>>,
conditions_decoder(),
fun(Conditions) ->
gleam@dynamic@decode:field(
<<"rules"/utf8>>,
gleam@dynamic@decode:list(rule_decoder()),
fun(Rules) ->
gleam@dynamic@decode:success({tree_rule, Conditions, Rules})
end
)
end
).
-file("src/aws/endpoints.gleam", 205).
-spec rule_decoder() -> gleam@dynamic@decode:decoder(rule()).
rule_decoder() ->
gleam@dynamic@decode:field(
<<"type"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Type_str) -> case Type_str of
<<"endpoint"/utf8>> ->
endpoint_rule_decoder();
<<"error"/utf8>> ->
error_rule_decoder();
<<"tree"/utf8>> ->
tree_rule_decoder();
_ ->
gleam@dynamic@decode:failure(
error_rule_failsafe(),
<<"unknown rule type"/utf8>>
)
end end
).
-file("src/aws/endpoints.gleam", 199).
-spec value_decoder() -> gleam@dynamic@decode:decoder(value()).
value_decoder() ->
gleam@dynamic@decode:one_of(
gleam@dynamic@decode:map(
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Field@0) -> {string_val, Field@0} end
),
[gleam@dynamic@decode:map(
{decoder, fun gleam@dynamic@decode:decode_bool/1},
fun(Field@0) -> {bool_val, Field@0} end
)]
).
-file("src/aws/endpoints.gleam", 174).
-spec parameter_decoder() -> gleam@dynamic@decode:decoder(parameter()).
parameter_decoder() ->
gleam@dynamic@decode:field(
<<"type"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Type_str) ->
gleam@dynamic@decode:optional_field(
<<"required"/utf8>>,
false,
{decoder, fun gleam@dynamic@decode:decode_bool/1},
fun(Required) ->
gleam@dynamic@decode:then(
gleam@dynamic@decode:optionally_at(
[<<"default"/utf8>>],
none,
gleam@dynamic@decode:map(
value_decoder(),
fun(Field@0) -> {some, Field@0} end
)
),
fun(Default) ->
gleam@dynamic@decode:then(
gleam@dynamic@decode:optionally_at(
[<<"builtIn"/utf8>>],
none,
gleam@dynamic@decode:map(
{decoder,
fun gleam@dynamic@decode:decode_string/1},
fun(Field@0) -> {some, Field@0} end
)
),
fun(Builtin) ->
Type_ = case string:lowercase(Type_str) of
<<"string"/utf8>> ->
string_type;
_ ->
boolean_type
end,
gleam@dynamic@decode:success(
{parameter,
Type_,
Required,
Default,
Builtin}
)
end
)
end
)
end
)
end
).
-file("src/aws/endpoints.gleam", 170).
-spec parameters_decoder() -> gleam@dynamic@decode:decoder(gleam@dict:dict(binary(), parameter())).
parameters_decoder() ->
gleam@dynamic@decode:dict(
{decoder, fun gleam@dynamic@decode:decode_string/1},
parameter_decoder()
).
-file("src/aws/endpoints.gleam", 164).
-spec rule_set_decoder() -> gleam@dynamic@decode:decoder(rule_set()).
rule_set_decoder() ->
gleam@dynamic@decode:field(
<<"parameters"/utf8>>,
parameters_decoder(),
fun(Parameters) ->
gleam@dynamic@decode:field(
<<"rules"/utf8>>,
gleam@dynamic@decode:list(rule_decoder()),
fun(Rules) ->
gleam@dynamic@decode:success({rule_set, Parameters, Rules})
end
)
end
).
-file("src/aws/endpoints.gleam", 92).
?DOC(
" Parse a rule set JSON document (as a Gleam string) into the internal AST.\n"
" The result is reusable across many `resolve` calls with different params.\n"
).
-spec parse_rule_set(binary()) -> {ok, rule_set()} | {error, resolve_error()}.
parse_rule_set(Json_text) ->
_pipe = gleam@json:parse(Json_text, rule_set_decoder()),
gleam@result:map_error(
_pipe,
fun(Err) -> {invalid_rule_set, describe_decode_error(Err)} end
).
-file("src/aws/endpoints.gleam", 458).
-spec is_truthy(value()) -> boolean().
is_truthy(Value) ->
case Value of
empty_val ->
false;
{bool_val, B} ->
B;
{list_val, []} ->
false;
{record_val, Fields} ->
case maps:size(Fields) of
0 ->
false;
_ ->
true
end;
_ ->
true
end.
-file("src/aws/endpoints.gleam", 900).
-spec is_int_string(binary()) -> boolean().
is_int_string(S) ->
case gleam_stdlib:parse_int(S) of
{ok, _} ->
true;
{error, _} ->
false
end.
-file("src/aws/endpoints.gleam", 893).
-spec all_ip4_segments(list(binary())) -> boolean().
all_ip4_segments(Parts) ->
case erlang:length(Parts) of
4 ->
gleam@list:all(Parts, fun(P) -> is_int_string(P) end);
_ ->
false
end.
-file("src/aws/endpoints.gleam", 880).
-spec looks_like_ip(binary()) -> boolean().
looks_like_ip(Authority) ->
Host = case gleam@string:split_once(Authority, <<":"/utf8>>) of
{ok, {H, _}} ->
H;
{error, _} ->
Authority
end,
case gleam_stdlib:string_starts_with(Host, <<"["/utf8>>) andalso gleam_stdlib:string_ends_with(
Host,
<<"]"/utf8>>
) of
true ->
true;
false ->
all_ip4_segments(gleam@string:split(Host, <<"."/utf8>>))
end.
-file("src/aws/endpoints.gleam", 1125).
-spec is_lower_alnum(binary()) -> boolean().
is_lower_alnum(C) ->
case C of
<<"0"/utf8>> ->
true;
<<"1"/utf8>> ->
true;
<<"2"/utf8>> ->
true;
<<"3"/utf8>> ->
true;
<<"4"/utf8>> ->
true;
<<"5"/utf8>> ->
true;
<<"6"/utf8>> ->
true;
<<"7"/utf8>> ->
true;
<<"8"/utf8>> ->
true;
<<"9"/utf8>> ->
true;
_ ->
case gleam@string:to_utf_codepoints(C) of
[Cp] ->
N = gleam_stdlib:identity(Cp),
(N >= 97) andalso (N =< 122);
_ ->
false
end
end.
-file("src/aws/endpoints.gleam", 1116).
-spec all_bucket_chars(list(binary())) -> boolean().
all_bucket_chars(Chars) ->
gleam@list:all(Chars, fun(C) -> case C of
<<"-"/utf8>> ->
true;
_ ->
is_lower_alnum(C)
end end).
-file("src/aws/endpoints.gleam", 1099).
-spec is_valid_bucket_label(binary()) -> boolean().
is_valid_bucket_label(Label) ->
Length = string:length(Label),
Bytes = erlang:byte_size(gleam_stdlib:identity(Label)),
case ((Length =:= Bytes) andalso (Length >= 3)) andalso (Length =< 63) of
false ->
false;
true ->
case Label of
<<""/utf8>> ->
false;
_ ->
((not gleam_stdlib:string_starts_with(Label, <<"-"/utf8>>)
andalso not gleam_stdlib:string_ends_with(
Label,
<<"-"/utf8>>
))
andalso all_bucket_chars(gleam@string:to_graphemes(Label)))
andalso not looks_like_ip(Label)
end
end.
-file("src/aws/endpoints.gleam", 1089).
-spec is_virtual_hostable(binary(), boolean()) -> boolean().
is_virtual_hostable(Name, Allow_subdomains) ->
case Allow_subdomains of
false ->
is_valid_bucket_label(Name);
true ->
_pipe = Name,
_pipe@1 = gleam@string:split(_pipe, <<"."/utf8>>),
gleam@list:all(_pipe@1, fun is_valid_bucket_label/1)
end.
-file("src/aws/endpoints.gleam", 986).
-spec do_split_resource(binary(), binary(), list(binary())) -> list(binary()).
do_split_resource(Input, Buf, Acc) ->
case gleam_stdlib:string_pop_grapheme(Input) of
{error, _} ->
lists:reverse([Buf | Acc]);
{ok, {C, Rest}} ->
case C of
<<"/"/utf8>> ->
do_split_resource(Rest, <<""/utf8>>, [Buf | Acc]);
<<":"/utf8>> ->
do_split_resource(Rest, <<""/utf8>>, [Buf | Acc]);
_ ->
do_split_resource(Rest, <<Buf/binary, C/binary>>, Acc)
end
end.
-file("src/aws/endpoints.gleam", 982).
-spec split_resource_chars(binary()) -> list(binary()).
split_resource_chars(Input) ->
do_split_resource(Input, <<""/utf8>>, []).
-file("src/aws/endpoints.gleam", 974).
?DOC(
" Resource-section splitter: break on either `/` or `:`, like the Go SDK's\n"
" `splitResource`.\n"
).
-spec split_resource_to_value(binary()) -> value().
split_resource_to_value(Resource) ->
_pipe = Resource,
_pipe@1 = split_resource_chars(_pipe),
_pipe@2 = gleam@list:index_map(
_pipe@1,
fun(Part, Idx) ->
{erlang:integer_to_binary(Idx), {string_val, Part}}
end
),
_pipe@3 = maps:from_list(_pipe@2),
{record_val, _pipe@3}.
-file("src/aws/endpoints.gleam", 956).
-spec do_split_n(binary(), binary(), integer(), list(binary())) -> list(binary()).
do_split_n(Input, Sep, N, Acc) ->
case N =< 1 of
true ->
lists:reverse([Input | Acc]);
false ->
case gleam@string:split_once(Input, Sep) of
{ok, {Head, Rest}} ->
do_split_n(Rest, Sep, N - 1, [Head | Acc]);
{error, _} ->
lists:reverse([Input | Acc])
end
end.
-file("src/aws/endpoints.gleam", 952).
?DOC(
" `strings.SplitN(input, sep, n)` — split into at most `n` parts; the last\n"
" part keeps any remaining separators as literal characters.\n"
).
-spec split_n(binary(), binary(), integer()) -> list(binary()).
split_n(Input, Sep, N) ->
do_split_n(Input, Sep, N, []).
-file("src/aws/endpoints.gleam", 928).
?DOC(
" Port of the Go SDK's `awsrulesfn.ParseARN`\n"
" (aws-sdk-go-v2/internal/endpoints/awsrulesfn/arn.go). Requires the\n"
" literal `arn:` prefix, splits into exactly six sections (so colons in\n"
" the resource section stay intact), requires non-empty partition /\n"
" service / resource, and splits the resource on either `:` or `/`.\n"
).
-spec parse_arn(binary()) -> value().
parse_arn(Arn) ->
case gleam_stdlib:string_starts_with(Arn, <<"arn:"/utf8>>) of
false ->
empty_val;
true ->
case split_n(Arn, <<":"/utf8>>, 6) of
[_, Partition, Service, Region, Account_id, Resource] when ((Partition =/= <<""/utf8>>) andalso (Service =/= <<""/utf8>>)) andalso (Resource =/= <<""/utf8>>) ->
{record_val,
maps:from_list(
[{<<"partition"/utf8>>, {string_val, Partition}},
{<<"service"/utf8>>, {string_val, Service}},
{<<"region"/utf8>>, {string_val, Region}},
{<<"accountId"/utf8>>, {string_val, Account_id}},
{<<"resourceId"/utf8>>,
split_resource_to_value(Resource)}]
)};
_ ->
empty_val
end
end.
-file("src/aws/endpoints.gleam", 1320).
?DOC(
" Classify a region into one of the AWS partitions. Mirrors the\n"
" `regionRegex` patterns from upstream `partitions.json`. Order matters:\n"
" the longest-prefix matchers (us-isob-, us-isof-) come first, then the\n"
" generic `us-iso-`.\n"
).
-spec classify_partition(binary()) -> partition().
classify_partition(Region) ->
case Region of
<<"aws-cn-global"/utf8>> ->
aws_cn;
<<"aws-us-gov-global"/utf8>> ->
aws_us_gov;
<<"aws-iso-global"/utf8>> ->
aws_iso;
<<"aws-iso-b-global"/utf8>> ->
aws_iso_b;
<<"aws-iso-e-global"/utf8>> ->
aws_iso_e;
<<"aws-iso-f-global"/utf8>> ->
aws_iso_f;
_ ->
case gleam_stdlib:string_starts_with(Region, <<"cn-"/utf8>>) orelse gleam_stdlib:string_starts_with(
Region,
<<"aws-cn-"/utf8>>
) of
true ->
aws_cn;
false ->
case gleam_stdlib:string_starts_with(
Region,
<<"us-gov-"/utf8>>
) of
true ->
aws_us_gov;
false ->
case gleam_stdlib:string_starts_with(
Region,
<<"eusc-"/utf8>>
) of
true ->
aws_eusc;
false ->
case gleam_stdlib:string_starts_with(
Region,
<<"us-isob-"/utf8>>
) of
true ->
aws_iso_b;
false ->
case gleam_stdlib:string_starts_with(
Region,
<<"us-isof-"/utf8>>
) of
true ->
aws_iso_f;
false ->
case gleam_stdlib:string_starts_with(
Region,
<<"us-iso-"/utf8>>
) of
true ->
aws_iso;
false ->
case gleam_stdlib:string_starts_with(
Region,
<<"eu-isoe-"/utf8>>
) of
true ->
aws_iso_e;
false ->
aws_commercial
end
end
end
end
end
end
end
end.
-file("src/aws/endpoints.gleam", 1227).
?DOC(
" Hardcoded partition data sourced from smithy-rs's `partitions.json`.\n"
" Refresh when AWS announces a new partition or DNS suffix.\n"
).
-spec partition_for(binary()) -> gleam@dict:dict(binary(), value()).
partition_for(Region) ->
Trimmed = gleam@string:trim(Region),
case classify_partition(Trimmed) of
aws_commercial ->
maps:from_list(
[{<<"name"/utf8>>, {string_val, <<"aws"/utf8>>}},
{<<"dnsSuffix"/utf8>>,
{string_val, <<"amazonaws.com"/utf8>>}},
{<<"dualStackDnsSuffix"/utf8>>,
{string_val, <<"api.aws"/utf8>>}},
{<<"supportsFIPS"/utf8>>, {bool_val, true}},
{<<"supportsDualStack"/utf8>>, {bool_val, true}},
{<<"implicitGlobalRegion"/utf8>>,
{string_val, <<"us-east-1"/utf8>>}}]
);
aws_cn ->
maps:from_list(
[{<<"name"/utf8>>, {string_val, <<"aws-cn"/utf8>>}},
{<<"dnsSuffix"/utf8>>,
{string_val, <<"amazonaws.com.cn"/utf8>>}},
{<<"dualStackDnsSuffix"/utf8>>,
{string_val, <<"api.amazonwebservices.com.cn"/utf8>>}},
{<<"supportsFIPS"/utf8>>, {bool_val, true}},
{<<"supportsDualStack"/utf8>>, {bool_val, true}},
{<<"implicitGlobalRegion"/utf8>>,
{string_val, <<"cn-northwest-1"/utf8>>}}]
);
aws_us_gov ->
maps:from_list(
[{<<"name"/utf8>>, {string_val, <<"aws-us-gov"/utf8>>}},
{<<"dnsSuffix"/utf8>>,
{string_val, <<"amazonaws.com"/utf8>>}},
{<<"dualStackDnsSuffix"/utf8>>,
{string_val, <<"api.aws"/utf8>>}},
{<<"supportsFIPS"/utf8>>, {bool_val, true}},
{<<"supportsDualStack"/utf8>>, {bool_val, true}},
{<<"implicitGlobalRegion"/utf8>>,
{string_val, <<"us-gov-west-1"/utf8>>}}]
);
aws_eusc ->
maps:from_list(
[{<<"name"/utf8>>, {string_val, <<"aws-eusc"/utf8>>}},
{<<"dnsSuffix"/utf8>>,
{string_val, <<"amazonaws.eu"/utf8>>}},
{<<"dualStackDnsSuffix"/utf8>>,
{string_val, <<"api.amazonwebservices.eu"/utf8>>}},
{<<"supportsFIPS"/utf8>>, {bool_val, true}},
{<<"supportsDualStack"/utf8>>, {bool_val, true}},
{<<"implicitGlobalRegion"/utf8>>,
{string_val, <<"eusc-de-east-1"/utf8>>}}]
);
aws_iso ->
maps:from_list(
[{<<"name"/utf8>>, {string_val, <<"aws-iso"/utf8>>}},
{<<"dnsSuffix"/utf8>>, {string_val, <<"c2s.ic.gov"/utf8>>}},
{<<"dualStackDnsSuffix"/utf8>>,
{string_val, <<"api.aws.ic.gov"/utf8>>}},
{<<"supportsFIPS"/utf8>>, {bool_val, true}},
{<<"supportsDualStack"/utf8>>, {bool_val, true}},
{<<"implicitGlobalRegion"/utf8>>,
{string_val, <<"us-iso-east-1"/utf8>>}}]
);
aws_iso_b ->
maps:from_list(
[{<<"name"/utf8>>, {string_val, <<"aws-iso-b"/utf8>>}},
{<<"dnsSuffix"/utf8>>,
{string_val, <<"sc2s.sgov.gov"/utf8>>}},
{<<"dualStackDnsSuffix"/utf8>>,
{string_val, <<"api.aws.scloud"/utf8>>}},
{<<"supportsFIPS"/utf8>>, {bool_val, true}},
{<<"supportsDualStack"/utf8>>, {bool_val, true}},
{<<"implicitGlobalRegion"/utf8>>,
{string_val, <<"us-isob-east-1"/utf8>>}}]
);
aws_iso_e ->
maps:from_list(
[{<<"name"/utf8>>, {string_val, <<"aws-iso-e"/utf8>>}},
{<<"dnsSuffix"/utf8>>,
{string_val, <<"cloud.adc-e.uk"/utf8>>}},
{<<"dualStackDnsSuffix"/utf8>>,
{string_val, <<"api.cloud-aws.adc-e.uk"/utf8>>}},
{<<"supportsFIPS"/utf8>>, {bool_val, true}},
{<<"supportsDualStack"/utf8>>, {bool_val, true}},
{<<"implicitGlobalRegion"/utf8>>,
{string_val, <<"eu-isoe-west-1"/utf8>>}}]
);
aws_iso_f ->
maps:from_list(
[{<<"name"/utf8>>, {string_val, <<"aws-iso-f"/utf8>>}},
{<<"dnsSuffix"/utf8>>,
{string_val, <<"csp.hci.ic.gov"/utf8>>}},
{<<"dualStackDnsSuffix"/utf8>>,
{string_val, <<"api.aws.hci.ic.gov"/utf8>>}},
{<<"supportsFIPS"/utf8>>, {bool_val, true}},
{<<"supportsDualStack"/utf8>>, {bool_val, true}},
{<<"implicitGlobalRegion"/utf8>>,
{string_val, <<"us-isof-south-1"/utf8>>}}]
)
end.
-file("src/aws/endpoints.gleam", 1062).
-spec is_digit(binary()) -> boolean().
is_digit(C) ->
case C of
<<"0"/utf8>> ->
true;
<<"1"/utf8>> ->
true;
<<"2"/utf8>> ->
true;
<<"3"/utf8>> ->
true;
<<"4"/utf8>> ->
true;
<<"5"/utf8>> ->
true;
<<"6"/utf8>> ->
true;
<<"7"/utf8>> ->
true;
<<"8"/utf8>> ->
true;
<<"9"/utf8>> ->
true;
_ ->
false
end.
-file("src/aws/endpoints.gleam", 1052).
-spec is_upper_alpha(binary()) -> boolean().
is_upper_alpha(C) ->
case gleam@string:to_utf_codepoints(C) of
[Cp] ->
N = gleam_stdlib:identity(Cp),
(N >= 65) andalso (N =< 90);
_ ->
false
end.
-file("src/aws/endpoints.gleam", 1043).
-spec all_host_label_chars(list(binary())) -> boolean().
all_host_label_chars(Chars) ->
gleam@list:all(Chars, fun(C) -> case C of
<<"-"/utf8>> ->
true;
_ ->
(is_lower_alnum(C) orelse is_upper_alpha(C)) orelse is_digit(
C
)
end end).
-file("src/aws/endpoints.gleam", 1031).
-spec is_one_host_label(binary()) -> boolean().
is_one_host_label(Label) ->
Length = string:length(Label),
Bytes = erlang:byte_size(gleam_stdlib:identity(Label)),
case ((Length =:= Bytes) andalso (Length >= 1)) andalso (Length =< 63) of
false ->
false;
true ->
(not gleam_stdlib:string_starts_with(Label, <<"-"/utf8>>) andalso not gleam_stdlib:string_ends_with(
Label,
<<"-"/utf8>>
))
andalso all_host_label_chars(gleam@string:to_graphemes(Label))
end.
-file("src/aws/endpoints.gleam", 1021).
-spec is_valid_host_label(binary(), boolean()) -> boolean().
is_valid_host_label(Name, Allow_subdomains) ->
case Allow_subdomains of
false ->
is_one_host_label(Name);
true ->
_pipe = Name,
_pipe@1 = gleam@string:split(_pipe, <<"."/utf8>>),
gleam@list:all(_pipe@1, fun is_one_host_label/1)
end.
-file("src/aws/endpoints.gleam", 838).
-spec do_parse_url_parts(binary(), binary()) -> value().
do_parse_url_parts(Scheme, After_scheme) ->
case gleam_stdlib:contains_string(After_scheme, <<"@"/utf8>>) orelse gleam_stdlib:contains_string(
After_scheme,
<<"#"/utf8>>
) of
true ->
empty_val;
false ->
{Authority, Path_and_query} = case gleam@string:split_once(
After_scheme,
<<"/"/utf8>>
) of
{ok, {A, Rest}} ->
{A, <<"/"/utf8, Rest/binary>>};
{error, _} ->
{After_scheme, <<""/utf8>>}
end,
Path = case gleam@string:split_once(Path_and_query, <<"?"/utf8>>) of
{ok, {P, _}} ->
P;
{error, _} ->
Path_and_query
end,
Normalized = case Path of
<<""/utf8>> ->
<<"/"/utf8>>;
_ ->
case gleam_stdlib:string_ends_with(Path, <<"/"/utf8>>) of
true ->
Path;
false ->
<<Path/binary, "/"/utf8>>
end
end,
Is_ip = looks_like_ip(Authority),
{record_val,
maps:from_list(
[{<<"scheme"/utf8>>, {string_val, Scheme}},
{<<"authority"/utf8>>, {string_val, Authority}},
{<<"path"/utf8>>, {string_val, Path}},
{<<"normalizedPath"/utf8>>, {string_val, Normalized}},
{<<"isIp"/utf8>>, {bool_val, Is_ip}}]
)}
end.
-file("src/aws/endpoints.gleam", 826).
-spec parse_url(binary()) -> value().
parse_url(Url) ->
case gleam@string:split_once(Url, <<"://"/utf8>>) of
{error, _} ->
empty_val;
{ok, {Scheme, Rest}} ->
case Scheme of
<<"http"/utf8>> ->
do_parse_url_parts(Scheme, Rest);
<<"https"/utf8>> ->
do_parse_url_parts(Scheme, Rest);
_ ->
empty_val
end
end.
-file("src/aws/endpoints.gleam", 1204).
-spec hex_digit(integer()) -> binary().
hex_digit(N) ->
case N of
0 ->
<<"0"/utf8>>;
1 ->
<<"1"/utf8>>;
2 ->
<<"2"/utf8>>;
3 ->
<<"3"/utf8>>;
4 ->
<<"4"/utf8>>;
5 ->
<<"5"/utf8>>;
6 ->
<<"6"/utf8>>;
7 ->
<<"7"/utf8>>;
8 ->
<<"8"/utf8>>;
9 ->
<<"9"/utf8>>;
10 ->
<<"A"/utf8>>;
11 ->
<<"B"/utf8>>;
12 ->
<<"C"/utf8>>;
13 ->
<<"D"/utf8>>;
14 ->
<<"E"/utf8>>;
_ ->
<<"F"/utf8>>
end.
-file("src/aws/endpoints.gleam", 1198).
-spec hex_byte(integer()) -> binary().
hex_byte(B) ->
High = B div 16,
Low = B rem 16,
<<(hex_digit(High))/binary, (hex_digit(Low))/binary>>.
-file("src/aws/endpoints.gleam", 1188).
-spec is_unreserved_byte(integer()) -> boolean().
is_unreserved_byte(B) ->
(((((((B >= 16#41) andalso (B =< 16#5A)) orelse ((B >= 16#61) andalso (B =< 16#7A)))
orelse ((B >= 16#30) andalso (B =< 16#39)))
orelse (B =:= 16#2D))
orelse (B =:= 16#5F))
orelse (B =:= 16#2E))
orelse (B =:= 16#7E).
-file("src/aws/endpoints.gleam", 1172).
-spec do_uri_encode(bitstring(), binary()) -> binary().
do_uri_encode(Bits, Acc) ->
case Bits of
<<>> ->
Acc;
<<B, Rest/bitstring>> ->
case is_unreserved_byte(B) of
true ->
case gleam@bit_array:to_string(<<B>>) of
{ok, S} ->
do_uri_encode(Rest, <<Acc/binary, S/binary>>);
{error, _} ->
do_uri_encode(
Rest,
<<<<Acc/binary, "%"/utf8>>/binary,
(hex_byte(B))/binary>>
)
end;
false ->
do_uri_encode(
Rest,
<<<<Acc/binary, "%"/utf8>>/binary,
(hex_byte(B))/binary>>
)
end;
_ ->
Acc
end.
-file("src/aws/endpoints.gleam", 1168).
?DOC(
" Single-component percent-encoding matching `aws/internal/uri.encode_component`.\n"
" Inlined to avoid a cross-module dependency.\n"
).
-spec aws_uri_encode(binary()) -> binary().
aws_uri_encode(Input) ->
do_uri_encode(gleam_stdlib:identity(Input), <<""/utf8>>).
-file("src/aws/endpoints.gleam", 801).
-spec percent_encode_uri(binary()) -> binary().
percent_encode_uri(Input) ->
case Input of
<<""/utf8>> ->
<<""/utf8>>;
_ ->
aws_uri_encode(Input)
end.
-file("src/aws/endpoints.gleam", 766).
-spec do_substring(binary(), integer(), integer(), boolean()) -> value().
do_substring(Input, Start, Stop, Reverse) ->
Length = string:length(Input),
Bytes = erlang:byte_size(gleam_stdlib:identity(Input)),
case Bytes /= Length of
true ->
empty_val;
false ->
case ((Start < 0) orelse (Stop > Length)) orelse (Start >= Stop) of
true ->
empty_val;
false ->
{Real_start, Real_stop} = case Reverse of
false ->
{Start, Stop};
true ->
{Length - Stop, Length - Start}
end,
{string_val,
gleam@string:slice(
Input,
Real_start,
Real_stop - Real_start
)}
end
end.
-file("src/aws/endpoints.gleam", 724).
-spec list_index(list(JOT), integer()) -> {ok, JOT} | {error, nil}.
list_index(Items, Idx) ->
case {Items, Idx} of
{[], _} ->
{error, nil};
{[Head | _], 0} ->
{ok, Head};
{[_ | Rest], N} when N > 0 ->
list_index(Rest, N - 1);
{_, _} ->
{error, nil}
end.
-file("src/aws/endpoints.gleam", 700).
-spec traverse_value(value(), list(binary())) -> value().
traverse_value(Value, Path) ->
case Path of
[] ->
Value;
[First | Rest] ->
case Value of
{record_val, Fields} ->
case gleam_stdlib:map_get(Fields, First) of
{ok, Inner} ->
traverse_value(Inner, Rest);
{error, _} ->
empty_val
end;
{list_val, Items} ->
case gleam_stdlib:parse_int(First) of
{ok, Idx} ->
case list_index(Items, Idx) of
{ok, Inner@1} ->
traverse_value(Inner@1, Rest);
{error, _} ->
empty_val
end;
{error, _} ->
empty_val
end;
_ ->
empty_val
end
end.
-file("src/aws/endpoints.gleam", 693).
?DOC(
" Parse a getAttr path into a list of segments. `\"service\"` → `[\"service\"]`,\n"
" `\"resourceId[0]\"` → `[\"resourceId\", \"0\"]`, `\"a[1][2]\"` → `[\"a\",\"1\",\"2\"]`.\n"
).
-spec parse_attr_path(binary()) -> list(binary()).
parse_attr_path(Path) ->
_pipe = Path,
_pipe@1 = gleam@string:split(_pipe, <<"["/utf8>>),
_pipe@2 = gleam@list:map(
_pipe@1,
fun(Segment) ->
gleam@string:replace(Segment, <<"]"/utf8>>, <<""/utf8>>)
end
),
gleam@list:filter(_pipe@2, fun(S) -> S /= <<""/utf8>> end).
-file("src/aws/endpoints.gleam", 582).
-spec value_to_string(value()) -> {ok, binary()} | {error, resolve_error()}.
value_to_string(Value) ->
case Value of
{string_val, S} ->
{ok, S};
{bool_val, true} ->
{ok, <<"true"/utf8>>};
{bool_val, false} ->
{ok, <<"false"/utf8>>};
empty_val ->
{ok, <<""/utf8>>};
{record_val, _} ->
{error, {unsupported, <<"cannot stringify record"/utf8>>}};
{list_val, _} ->
{error, {unsupported, <<"cannot stringify list"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 564).
-spec traverse_record(value(), list(binary())) -> {ok, value()} |
{error, resolve_error()}.
traverse_record(Value, Path) ->
case Path of
[] ->
{ok, Value};
[Field | Rest] ->
case Value of
{record_val, Fields} ->
case gleam_stdlib:map_get(Fields, Field) of
{ok, Inner} ->
traverse_record(Inner, Rest);
{error, _} ->
{ok, empty_val}
end;
_ ->
{ok, empty_val}
end
end.
-file("src/aws/endpoints.gleam", 550).
-spec lookup_path(list(binary()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
lookup_path(Path, Scope) ->
case Path of
[] ->
{ok, empty_val};
[First | Rest] ->
case gleam_stdlib:map_get(Scope, First) of
{error, _} ->
{ok, empty_val};
{ok, Value} ->
traverse_record(Value, Rest)
end
end.
-file("src/aws/endpoints.gleam", 534).
-spec do_eval_template(
list(template_part()),
gleam@dict:dict(binary(), value()),
binary()
) -> {ok, binary()} | {error, resolve_error()}.
do_eval_template(Parts, Scope, Acc) ->
case Parts of
[] ->
{ok, Acc};
[{static, Text} | Rest] ->
do_eval_template(Rest, Scope, <<Acc/binary, Text/binary>>);
[{interp, Path} | Rest@1] ->
gleam@result:'try'(
lookup_path(Path, Scope),
fun(Value) ->
gleam@result:'try'(
value_to_string(Value),
fun(Text@1) ->
do_eval_template(
Rest@1,
Scope,
<<Acc/binary, Text@1/binary>>
)
end
)
end
)
end.
-file("src/aws/endpoints.gleam", 527).
-spec eval_template(list(template_part()), gleam@dict:dict(binary(), value())) -> {ok,
binary()} |
{error, resolve_error()}.
eval_template(Parts, Scope) ->
do_eval_template(Parts, Scope, <<""/utf8>>).
-file("src/aws/endpoints.gleam", 1158).
-spec eval_to_bool(expr(), gleam@dict:dict(binary(), value())) -> {ok,
boolean()} |
{error, resolve_error()}.
eval_to_bool(Expr, Scope) ->
gleam@result:'try'(eval(Expr, Scope), fun(Value) -> case Value of
{bool_val, B} ->
{ok, B};
_ ->
{error, {unsupported, <<"expected a boolean"/utf8>>}}
end end).
-file("src/aws/endpoints.gleam", 515).
-spec eval_to_string(expr(), gleam@dict:dict(binary(), value())) -> {ok,
binary()} |
{error, resolve_error()}.
eval_to_string(Expr, Scope) ->
gleam@result:'try'(eval(Expr, Scope), fun(Value) -> case Value of
{string_val, S} ->
{ok, S};
{bool_val, true} ->
{ok, <<"true"/utf8>>};
{bool_val, false} ->
{ok, <<"false"/utf8>>};
empty_val ->
{ok, <<""/utf8>>};
{record_val, _} ->
{error,
{unsupported, <<"cannot stringify record value"/utf8>>}};
{list_val, _} ->
{error,
{unsupported, <<"cannot stringify list value"/utf8>>}}
end end).
-file("src/aws/endpoints.gleam", 1071).
?DOC(
" DNS-3-to-63-char rules + S3 bucket constraints: lowercase letters, digits,\n"
" hyphens; not IP-shaped; doesn't begin or end with a hyphen.\n"
).
-spec bi_is_virtual_hostable_s3_bucket(
list(expr()),
gleam@dict:dict(binary(), value())
) -> {ok, value()} | {error, resolve_error()}.
bi_is_virtual_hostable_s3_bucket(Args, Scope) ->
case Args of
[Name_expr, Allow_subdomains_expr] ->
gleam@result:'try'(
eval_to_string(Name_expr, Scope),
fun(Name) ->
gleam@result:'try'(
eval_to_bool(Allow_subdomains_expr, Scope),
fun(Allow_subdomains) ->
{ok,
{bool_val,
is_virtual_hostable(Name, Allow_subdomains)}}
end
)
end
);
_ ->
{error,
{unsupported,
<<"aws.isVirtualHostableS3Bucket expects 2 args"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 910).
?DOC(
" Parse an AWS ARN: `arn:partition:service:region:accountId:resource`. The\n"
" resource is whatever comes after the fifth colon. Returns `EmptyVal` if\n"
" the input doesn't have at least 6 colon-separated parts.\n"
).
-spec bi_aws_parse_arn(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_aws_parse_arn(Args, Scope) ->
case Args of
[Arg] ->
gleam@result:'try'(
eval_to_string(Arg, Scope),
fun(Arn) -> {ok, parse_arn(Arn)} end
);
_ ->
{error, {unsupported, <<"aws.parseArn expects 1 argument"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 733).
-spec bi_aws_partition(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_aws_partition(Args, Scope) ->
case Args of
[Region_expr] ->
gleam@result:'try'(
eval_to_string(Region_expr, Scope),
fun(Region) -> {ok, {record_val, partition_for(Region)}} end
);
_ ->
{error, {unsupported, <<"aws.partition expects 1 argument"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 1004).
?DOC(
" RFC 1123 host label validation. Accepts ASCII letters/digits/hyphens, no\n"
" leading/trailing hyphen, length 1..63. With `allowSubdomains=true` the\n"
" label may be `.`-separated and each piece is validated independently.\n"
).
-spec bi_is_valid_host_label(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_is_valid_host_label(Args, Scope) ->
case Args of
[Name_expr, Allow_subdomains_expr] ->
gleam@result:'try'(
eval_to_string(Name_expr, Scope),
fun(Name) ->
gleam@result:'try'(
eval_to_bool(Allow_subdomains_expr, Scope),
fun(Allow_subdomains) ->
{ok,
{bool_val,
is_valid_host_label(Name, Allow_subdomains)}}
end
)
end
);
_ ->
{error,
{unsupported, <<"isValidHostLabel expects 2 arguments"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 813).
?DOC(
" Parse a URL into `{ scheme, authority, path, normalizedPath, isIp }`.\n"
" Returns `EmptyVal` if the URL doesn't look well-formed. We support the\n"
" shapes AWS rule sets actually pass us; this is not a full RFC 3986\n"
" parser.\n"
).
-spec bi_parse_url(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_parse_url(Args, Scope) ->
case Args of
[Arg] ->
gleam@result:'try'(
eval_to_string(Arg, Scope),
fun(Url) -> {ok, parse_url(Url)} end
);
_ ->
{error, {unsupported, <<"parseURL expects 1 argument"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 788).
?DOC(" Percent-encode a URI component.\n").
-spec bi_uri_encode(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_uri_encode(Args, Scope) ->
case Args of
[Arg] ->
gleam@result:'try'(
eval_to_string(Arg, Scope),
fun(Input) -> {ok, {string_val, percent_encode_uri(Input)}} end
);
_ ->
{error, {unsupported, <<"uriEncode expects 1 argument"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 1141).
-spec eval_to_int(expr(), gleam@dict:dict(binary(), value())) -> {ok, integer()} |
{error, resolve_error()}.
eval_to_int(Expr, Scope) ->
case Expr of
{int_lit, N} ->
{ok, N};
_ ->
gleam@result:'try'(eval(Expr, Scope), fun(Value) -> case Value of
{string_val, S} ->
case gleam_stdlib:parse_int(S) of
{ok, N@1} ->
{ok, N@1};
{error, _} ->
{error,
{unsupported,
<<"non-integer string: "/utf8,
S/binary>>}}
end;
_ ->
{error,
{unsupported, <<"expected an integer"/utf8>>}}
end end)
end.
-file("src/aws/endpoints.gleam", 750).
?DOC(
" `substring(input, start, stop, reverse)` — Smithy spec says the result is\n"
" empty (returns `EmptyVal`) if any character is non-ASCII, or if the range\n"
" is invalid. With `reverse=true` the indexes count from the end of the\n"
" string.\n"
).
-spec bi_substring(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_substring(Args, Scope) ->
case Args of
[Input_expr, Start_expr, Stop_expr, Reverse_expr] ->
gleam@result:'try'(
eval_to_string(Input_expr, Scope),
fun(Input) ->
gleam@result:'try'(
eval_to_int(Start_expr, Scope),
fun(Start) ->
gleam@result:'try'(
eval_to_int(Stop_expr, Scope),
fun(Stop) ->
gleam@result:'try'(
eval_to_bool(Reverse_expr, Scope),
fun(Reverse) ->
{ok,
do_substring(
Input,
Start,
Stop,
Reverse
)}
end
)
end
)
end
)
end
);
_ ->
{error, {unsupported, <<"substring expects 4 arguments"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 677).
-spec bi_get_attr(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_get_attr(Args, Scope) ->
case Args of
[Obj, Key] ->
gleam@result:'try'(
eval(Obj, Scope),
fun(Record) ->
gleam@result:'try'(
eval_to_string(Key, Scope),
fun(Key_str) ->
Path = parse_attr_path(Key_str),
{ok, traverse_value(Record, Path)}
end
)
end
);
_ ->
{error, {unsupported, <<"getAttr expects 2 arguments"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 663).
-spec bi_string_equals(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_string_equals(Args, Scope) ->
case Args of
[A, B] ->
gleam@result:'try'(
eval_to_string(A, Scope),
fun(Sa) ->
gleam@result:'try'(
eval_to_string(B, Scope),
fun(Sb) -> {ok, {bool_val, Sa =:= Sb}} end
)
end
);
_ ->
{error, {unsupported, <<"stringEquals expects 2 arguments"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 644).
-spec bi_boolean_equals(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_boolean_equals(Args, Scope) ->
case Args of
[A, B] ->
gleam@result:'try'(
eval(A, Scope),
fun(Va) ->
gleam@result:'try'(
eval(B, Scope),
fun(Vb) -> {ok, {bool_val, case {Va, Vb} of
{{bool_val, X}, {bool_val, Y}} ->
X =:= Y;
{_, _} ->
false
end}} end
)
end
);
_ ->
{error, {unsupported, <<"booleanEquals expects 2 arguments"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 634).
-spec bi_not(list(expr()), gleam@dict:dict(binary(), value())) -> {ok, value()} |
{error, resolve_error()}.
bi_not(Args, Scope) ->
case Args of
[Arg] ->
gleam@result:'try'(
eval(Arg, Scope),
fun(Value) -> {ok, {bool_val, not is_truthy(Value)}} end
);
_ ->
{error, {unsupported, <<"not expects 1 argument"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 619).
-spec bi_is_set(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
bi_is_set(Args, Scope) ->
case Args of
[Arg] ->
gleam@result:'try'(
eval(Arg, Scope),
fun(Value) -> {ok, {bool_val, case Value of
empty_val ->
false;
_ ->
true
end}} end
);
_ ->
{error, {unsupported, <<"isSet expects 1 argument"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 593).
-spec eval_builtin(binary(), list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
value()} |
{error, resolve_error()}.
eval_builtin(Name, Args, Scope) ->
case Name of
<<"isSet"/utf8>> ->
bi_is_set(Args, Scope);
<<"not"/utf8>> ->
bi_not(Args, Scope);
<<"booleanEquals"/utf8>> ->
bi_boolean_equals(Args, Scope);
<<"stringEquals"/utf8>> ->
bi_string_equals(Args, Scope);
<<"getAttr"/utf8>> ->
bi_get_attr(Args, Scope);
<<"substring"/utf8>> ->
bi_substring(Args, Scope);
<<"uriEncode"/utf8>> ->
bi_uri_encode(Args, Scope);
<<"parseURL"/utf8>> ->
bi_parse_url(Args, Scope);
<<"isValidHostLabel"/utf8>> ->
bi_is_valid_host_label(Args, Scope);
<<"aws.partition"/utf8>> ->
bi_aws_partition(Args, Scope);
<<"aws.parseArn"/utf8>> ->
bi_aws_parse_arn(Args, Scope);
<<"aws.isVirtualHostableS3Bucket"/utf8>> ->
bi_is_virtual_hostable_s3_bucket(Args, Scope);
_ ->
{error,
{unsupported,
<<<<"endpoint rule builtin '"/utf8, Name/binary>>/binary,
"' not implemented"/utf8>>}}
end.
-file("src/aws/endpoints.gleam", 499).
-spec eval(expr(), gleam@dict:dict(binary(), value())) -> {ok, value()} |
{error, resolve_error()}.
eval(Expr, Scope) ->
case Expr of
{ref, Name} ->
case gleam_stdlib:map_get(Scope, Name) of
{ok, Value} ->
{ok, Value};
{error, _} ->
{ok, empty_val}
end;
{bool_lit, Value@1} ->
{ok, {bool_val, Value@1}};
{int_lit, N} ->
{ok, {string_val, erlang:integer_to_binary(N)}};
{template_expr, Parts} ->
_pipe = eval_template(Parts, Scope),
gleam@result:map(_pipe, fun(Field@0) -> {string_val, Field@0} end);
{fn_call, Name@1, Args} ->
eval_builtin(Name@1, Args, Scope)
end.
-file("src/aws/endpoints.gleam", 435).
-spec do_check(list(condition()), gleam@dict:dict(binary(), value())) -> {ok,
gleam@option:option(gleam@dict:dict(binary(), value()))} |
{error, resolve_error()}.
do_check(Conditions, Scope) ->
case Conditions of
[] ->
{ok, {some, Scope}};
[{condition, Expr, Assign} | Rest] ->
gleam@result:'try'(
eval(Expr, Scope),
fun(Value) -> case is_truthy(Value) of
false ->
{ok, none};
true ->
Scope@1 = case Assign of
{some, Name} ->
gleam@dict:insert(Scope, Name, Value);
none ->
Scope
end,
do_check(Rest, Scope@1)
end end
)
end.
-file("src/aws/endpoints.gleam", 428).
-spec check_conditions(list(condition()), gleam@dict:dict(binary(), value())) -> {ok,
gleam@option:option(gleam@dict:dict(binary(), value()))} |
{error, resolve_error()}.
check_conditions(Conditions, Scope) ->
do_check(Conditions, Scope).
-file("src/aws/endpoints.gleam", 485).
-spec eval_string_list(list(expr()), gleam@dict:dict(binary(), value())) -> {ok,
list(binary())} |
{error, resolve_error()}.
eval_string_list(Exprs, Scope) ->
case Exprs of
[] ->
{ok, []};
[Head | Tail] ->
gleam@result:'try'(
eval_to_string(Head, Scope),
fun(H) ->
gleam@result:'try'(
eval_string_list(Tail, Scope),
fun(T) -> {ok, [H | T]} end
)
end
)
end.
-file("src/aws/endpoints.gleam", 474).
-spec eval_headers(
gleam@dict:dict(binary(), list(expr())),
gleam@dict:dict(binary(), value())
) -> {ok, gleam@dict:dict(binary(), list(binary()))} | {error, resolve_error()}.
eval_headers(Headers, Scope) ->
gleam@dict:fold(
Headers,
{ok, maps:new()},
fun(Acc, Key, Exprs) ->
gleam@result:'try'(
Acc,
fun(Current) ->
gleam@result:'try'(
eval_string_list(Exprs, Scope),
fun(Values) ->
{ok, gleam@dict:insert(Current, Key, Values)}
end
)
end
)
end
).
-file("src/aws/endpoints.gleam", 388).
?DOC(
" `Ok(Some(_))` — matched + produced an endpoint\n"
" `Ok(None)` — conditions didn't match; try the next rule\n"
" `Error(_)` — an error rule fired, or evaluation hit an error\n"
).
-spec try_rule(rule(), gleam@dict:dict(binary(), value())) -> {ok,
gleam@option:option(endpoint())} |
{error, resolve_error()}.
try_rule(Rule, Scope) ->
case Rule of
{endpoint_rule, Conditions, Endpoint} ->
case check_conditions(Conditions, Scope) of
{ok, none} ->
{ok, none};
{ok, {some, New_scope}} ->
gleam@result:'try'(
eval_to_string(erlang:element(2, Endpoint), New_scope),
fun(Url) ->
gleam@result:'try'(
eval_headers(
erlang:element(3, Endpoint),
New_scope
),
fun(Headers) ->
{ok, {some, {endpoint, Url, Headers}}}
end
)
end
);
{error, Reason} ->
{error, Reason}
end;
{error_rule, Conditions@1, Message} ->
case check_conditions(Conditions@1, Scope) of
{ok, none} ->
{ok, none};
{ok, {some, New_scope@1}} ->
gleam@result:'try'(
eval_to_string(Message, New_scope@1),
fun(Text) -> {error, {rule_error, Text}} end
);
{error, Reason@1} ->
{error, Reason@1}
end;
{tree_rule, Conditions@2, Nested} ->
case check_conditions(Conditions@2, Scope) of
{ok, none} ->
{ok, none};
{ok, {some, New_scope@2}} ->
case evaluate_rules(Nested, New_scope@2) of
{ok, Endpoint@1} ->
{ok, {some, Endpoint@1}};
{error, no_match} ->
{ok, none};
{error, Reason@2} ->
{error, Reason@2}
end;
{error, Reason@3} ->
{error, Reason@3}
end
end.
-file("src/aws/endpoints.gleam", 370).
-spec evaluate_rules(list(rule()), gleam@dict:dict(binary(), value())) -> {ok,
endpoint()} |
{error, resolve_error()}.
evaluate_rules(Rules, Scope) ->
case Rules of
[] ->
{error, no_match};
[Rule | Rest] ->
case try_rule(Rule, Scope) of
{ok, {some, Endpoint}} ->
{ok, Endpoint};
{ok, none} ->
evaluate_rules(Rest, Scope);
{error, Reason} ->
{error, Reason}
end
end.
-file("src/aws/endpoints.gleam", 349).
-spec apply_defaults_and_check_required(
rule_set(),
gleam@dict:dict(binary(), value())
) -> {ok, gleam@dict:dict(binary(), value())} | {error, resolve_error()}.
apply_defaults_and_check_required(Rule_set, Params) ->
gleam@dict:fold(
erlang:element(2, Rule_set),
{ok, Params},
fun(Acc, Name, Parameter) ->
gleam@result:'try'(
Acc,
fun(Current) -> case gleam_stdlib:map_get(Current, Name) of
{ok, _} ->
{ok, Current};
{error, _} ->
case erlang:element(4, Parameter) of
{some, Value} ->
{ok,
gleam@dict:insert(Current, Name, Value)};
none ->
case erlang:element(3, Parameter) of
true ->
{error,
{required_parameter_missing,
Name}};
false ->
{ok, Current}
end
end
end end
)
end
).
-file("src/aws/endpoints.gleam", 102).
?DOC(
" Walk the rule set with the given parameters. Returns the first matching\n"
" endpoint, the first matching error rule (surfaced as `RuleError`), or\n"
" `NoMatch` if every rule's conditions failed.\n"
).
-spec resolve(rule_set(), gleam@dict:dict(binary(), value())) -> {ok,
endpoint()} |
{error, resolve_error()}.
resolve(Rule_set, Params) ->
gleam@result:'try'(
apply_defaults_and_check_required(Rule_set, Params),
fun(Prepared) ->
evaluate_rules(erlang:element(3, Rule_set), Prepared)
end
).