-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, <>} | Acc] ); {ok, {Before_brace, Rest_with_brace}} -> case gleam@string:split_once(Rest_with_brace, <<"}"/utf8>>) of {error, _} -> lists:reverse( [{static, <>} | Acc] ); {ok, {Interp_body, After_close}} -> New_static = <>, 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, <>, 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 -> <> 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; <> -> case is_unreserved_byte(B) of true -> case gleam@bit_array:to_string(<>) of {ok, S} -> do_uri_encode(Rest, <>); {error, _} -> do_uri_encode( Rest, <<<>/binary, (hex_byte(B))/binary>> ) end; false -> do_uri_encode( Rest, <<<>/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(JNQ), integer()) -> {ok, JNQ} | {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, <>); [{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, <> ) 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 ).