-module(typeid). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/typeid.gleam"). -export([prefix/1, suffix/1, to_string/1, uuid/1, from_uuid/2, new/1, parse/1, decode/1]). -export_type([type_id/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -opaque type_id(ELF) :: {type_id, binary(), binary()} | {gleam_phantom, ELF}. -file("src/typeid.gleam", 134). ?DOC( " Returns the prefix of the TypeId.\n" "\n" " ### Usage\n" " ```gleam\n" " let assert Ok(id) = new(\"user\")\n" " prefix(id) // \"user\"\n" " ```\n" ). -spec prefix(type_id(any())) -> binary(). prefix(Typeid) -> erlang:element(2, Typeid). -file("src/typeid.gleam", 145). ?DOC( " Returns the suffix of the TypeId.\n" "\n" " ### Usage\n" " ```gleam\n" " let assert Ok(id) = new(\"user\")\n" " suffix(id) // \"01h455vb4pex5vsknk084sn02q\"\n" " ```\n" ). -spec suffix(type_id(any())) -> binary(). suffix(Typeid) -> erlang:element(3, Typeid). -file("src/typeid.gleam", 159). ?DOC( " Returns the string representation of a TypeId.\n" "\n" " ### Usage\n" " ```gleam\n" " let assert Ok(id) = new(\"user\")\n" " to_string(id) // \"user_01h455vb4pex5vsknk084sn02q\"\n" "\n" " let assert Ok(id) = new(\"\")\n" " to_string(id) // \"01h455vb4pex5vsknk084sn02q\"\n" " ```\n" ). -spec to_string(type_id(any())) -> binary(). to_string(Typeid) -> case erlang:element(2, Typeid) of <<""/utf8>> -> erlang:element(3, Typeid); _ -> <<<<(erlang:element(2, Typeid))/binary, "_"/utf8>>/binary, (erlang:element(3, Typeid))/binary>> end. -file("src/typeid.gleam", 166). -spec prefix_suffix(binary()) -> {ok, {binary(), binary()}} | {error, nil}. prefix_suffix(Raw_typeid) -> _pipe = gleam@string:reverse(Raw_typeid), _pipe@1 = gleam@string:split_once(_pipe, <<"_"/utf8>>), gleam@result:'try'( _pipe@1, fun(Sp) -> {Xiffus, Xiferp} = Sp, Prefix = gleam@string:reverse(Xiferp), Suffix = gleam@string:reverse(Xiffus), {ok, {Prefix, Suffix}} end ). -file("src/typeid.gleam", 206). -spec index_to_alphabet(integer()) -> binary(). index_to_alphabet(Index) -> case Index 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>>; 15 -> <<"f"/utf8>>; 16 -> <<"g"/utf8>>; 17 -> <<"h"/utf8>>; 18 -> <<"j"/utf8>>; 19 -> <<"k"/utf8>>; 20 -> <<"m"/utf8>>; 21 -> <<"n"/utf8>>; 22 -> <<"p"/utf8>>; 23 -> <<"q"/utf8>>; 24 -> <<"r"/utf8>>; 25 -> <<"s"/utf8>>; 26 -> <<"t"/utf8>>; 27 -> <<"v"/utf8>>; 28 -> <<"w"/utf8>>; 29 -> <<"x"/utf8>>; 30 -> <<"y"/utf8>>; 31 -> <<"z"/utf8>>; _ -> <<"0"/utf8>> end. -file("src/typeid.gleam", 184). ?DOC(" Recursively grabs 5 bits and uses them as index in the alphabet and concatinate them to a string.\n"). -spec encode_bits_base32(bitstring(), binary()) -> binary(). encode_bits_base32(Binary, Acc) -> case Binary of <> -> encode_bits_base32( Rest, <> ); _ -> Acc end. -file("src/typeid.gleam", 178). -spec encode_base32(bitstring()) -> binary(). encode_base32(Bits) -> encode_bits_base32(<<0:2, Bits:128/bitstring>>, <<""/utf8>>). -file("src/typeid.gleam", 244). -spec alphabet_to_index(binary()) -> integer(). alphabet_to_index(Char) -> case Char of <<"0"/utf8>> -> 0; <<"1"/utf8>> -> 1; <<"2"/utf8>> -> 2; <<"3"/utf8>> -> 3; <<"4"/utf8>> -> 4; <<"5"/utf8>> -> 5; <<"6"/utf8>> -> 6; <<"7"/utf8>> -> 7; <<"8"/utf8>> -> 8; <<"9"/utf8>> -> 9; <<"a"/utf8>> -> 10; <<"b"/utf8>> -> 11; <<"c"/utf8>> -> 12; <<"d"/utf8>> -> 13; <<"e"/utf8>> -> 14; <<"f"/utf8>> -> 15; <<"g"/utf8>> -> 16; <<"h"/utf8>> -> 17; <<"j"/utf8>> -> 18; <<"k"/utf8>> -> 19; <<"m"/utf8>> -> 20; <<"n"/utf8>> -> 21; <<"p"/utf8>> -> 22; <<"q"/utf8>> -> 23; <<"r"/utf8>> -> 24; <<"s"/utf8>> -> 25; <<"t"/utf8>> -> 26; <<"v"/utf8>> -> 27; <<"w"/utf8>> -> 28; <<"x"/utf8>> -> 29; <<"y"/utf8>> -> 30; <<"z"/utf8>> -> 31; _ -> 0 end. -file("src/typeid.gleam", 192). -spec decode_base32(binary()) -> {ok, bitstring()} | {error, nil}. decode_base32(Enc_suffix) -> Bits = begin _pipe = gleam@string:to_graphemes(Enc_suffix), gleam@list:fold( _pipe, <<>>, fun(Acc, C) -> Index = alphabet_to_index(C), <> end ) end, case Bits of <<0:2, Res:128/bitstring>> -> {ok, Res}; _ -> {error, nil} end. -file("src/typeid.gleam", 122). ?DOC( " Returns the UUID string representation of the TypeId suffix.\n" "\n" " ### Usage\n" " ```gleam\n" " let assert Ok(id) = new(\"user\")\n" " uuid(id) // \"0110c853-1d09-52d8-d73e-1194e95b5f19\"\n" " ```\n" ). -spec uuid(type_id(any())) -> binary(). uuid(Typeid) -> Bits@1 = case decode_base32(erlang:element(3, Typeid)) of {ok, Bits} -> Bits; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"typeid"/utf8>>, function => <<"uuid"/utf8>>, line => 123, value => _assert_fail, start => 3394, 'end' => 3444, pattern_start => 3405, pattern_end => 3413}) end, typeid@uuid:to_string(Bits@1). -file("src/typeid.gleam", 39). ?DOC( " Generate a TypeID using the supplied prefix and UUID.\n" "\n" " ### Usage\n" " ```gleam\n" " let assert Ok(id) = from_uuid(\"user\", \"018fcec0-b44b-7ce2-b187-2f08349beab9\")\n" " ```\n" ). -spec from_uuid(binary(), binary()) -> {ok, type_id(any())} | {error, binary()}. from_uuid(Prefix, Uuid) -> Re@1 = case gleam@regexp:from_string( <<"^([a-z]([a-z_]{0,61}[a-z])?)?$"/utf8>> ) of {ok, Re} -> Re; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"typeid"/utf8>>, function => <<"from_uuid"/utf8>>, line => 43, value => _assert_fail, start => 1145, 'end' => 1197, pattern_start => 1156, pattern_end => 1162}) end, case gleam@regexp:check(Re@1, Prefix) of true -> case typeid@uuid:from_string(Uuid) of {ok, Uuid@1} -> Suffix = encode_base32(Uuid@1), _pipe = {type_id, Prefix, Suffix}, {ok, _pipe}; {error, _} -> {error, <<"Invalid UUID"/utf8>>} end; false -> _pipe@1 = <<"Prefix must contain at most 63 characters and only lowercase alphabetic ASCII characters [a-z], or an underscore."/utf8>>, {error, _pipe@1} end. -file("src/typeid.gleam", 29). ?DOC( " Create a new TypeId with the given prefix.\n" " Prefix must be a string containing at most 63 characters and only lowercase\n" " alphabetic ASCII characters [a-z], or an underscore.\n" " The prefix may also be empty.\n" "\n" " ### Usage\n" " ```gleam\n" " let assert Ok(id) = new(\"user\")\n" " ```\n" ). -spec new(binary()) -> {ok, type_id(any())} | {error, binary()}. new(Prefix) -> from_uuid(Prefix, typeid@uuid:v7()). -file("src/typeid.gleam", 69). ?DOC( " Parse a TypeId from a string.\n" " \n" " ### Usage\n" " ```gleam\n" " let assert Ok(id) = parse(\"user_01h455vb4pex5vsknk084sn02q\")\n" " ```\n" ). -spec parse(binary()) -> {ok, type_id(any())} | {error, binary()}. parse(Raw_typeid) -> Rs@1 = case gleam@regexp:from_string( <<"^[01234567][0123456789abcdefghjkmnpqrstvwxyz]{25}$"/utf8>> ) of {ok, Rs} -> Rs; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"typeid"/utf8>>, function => <<"parse"/utf8>>, line => 70, value => _assert_fail, start => 1828, 'end' => 1880, pattern_start => 1839, pattern_end => 1845}) end, case prefix_suffix(Raw_typeid) of {ok, {Prefix, Suffix}} when Prefix =/= <<""/utf8>> -> Rp@1 = case gleam@regexp:from_string( <<"^([a-z]([a-z_]{0,61}[a-z])?)?$"/utf8>> ) of {ok, Rp} -> Rp; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"typeid"/utf8>>, function => <<"parse"/utf8>>, line => 74, value => _assert_fail@1, start => 1970, 'end' => 2022, pattern_start => 1981, pattern_end => 1987}) end, gleam@bool:guard( not gleam@regexp:check(Rp@1, Prefix), {error, <<"Prefix is malformed"/utf8>>}, fun() -> gleam@bool:guard( not gleam@regexp:check(Rs@1, Suffix), {error, <<"Suffix is malformed"/utf8>>}, fun() -> _pipe = {type_id, Prefix, Suffix}, {ok, _pipe} end ) end ); _ -> gleam@bool:guard( not gleam@regexp:check(Rs@1, Raw_typeid), {error, <<"Suffix is malformed"/utf8>>}, fun() -> _pipe@1 = {type_id, <<""/utf8>>, Raw_typeid}, {ok, _pipe@1} end ) end. -file("src/typeid.gleam", 104). ?DOC( " TypeId decoder for use in Gleam's `decode` module.\n" " When decoding the type(prefix) is known, which is why this function takes\n" " the prefix as an argument to verify the prefix of the TypeId.\n" "\n" " ### Usage\n" " ```gleam\n" " let decoder = {\n" " use id <- decode.field(\"id\", typeid.decode(\"user\"))\n" " use name <- decode.field(\"name\", decode.string)\n" " decode.success(User(id:, name:))\n" " }\n" " ```\n" ). -spec decode(binary()) -> gleam@dynamic@decode:decoder(type_id(any())). decode(Kind) -> _pipe = {decoder, fun gleam@dynamic@decode:decode_string/1}, gleam@dynamic@decode:then( _pipe, fun(Id) -> case {prefix_suffix(Id), parse(Id)} of {{ok, {Prefix, _}}, {ok, Typeid}} when Prefix =:= Kind -> gleam@dynamic@decode:success(Typeid); {_, _} -> gleam@dynamic@decode:failure( {type_id, <<""/utf8>>, <<""/utf8>>}, <<"TypeId(a)"/utf8>> ) end end ).