-module(dot_env@internal@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([parse/1]). -spec expand_new_lines(binary()) -> binary(). expand_new_lines(Value) -> _pipe = gleam@string:replace(Value, <<"\\n"/utf8>>, <<"\n"/utf8>>), gleam@string:replace(_pipe, <<"\\r"/utf8>>, <<"\r"/utf8>>). -spec extract_value_from_match(gleam@regex:match()) -> {ok, binary()} | {error, binary()}. extract_value_from_match(Match) -> _pipe = gleam@list:at(erlang:element(3, Match), 1), _pipe@1 = gleam@result:unwrap(_pipe, {some, erlang:element(2, Match)}), _pipe@2 = gleam@option:unwrap(_pipe@1, <<""/utf8>>), {ok, _pipe@2}. -spec remove_surrounding_quotes(binary()) -> {ok, binary()} | {error, binary()}. remove_surrounding_quotes(Value) -> case gleam@regex:compile( <<"^(['\"`])([\\s\\S]*)\\1$"/utf8>>, {options, true, true} ) of {ok, Re} -> case gleam@regex:scan(Re, Value) of [Match] -> extract_value_from_match(Match); [_ | _] -> {error, <<"Multiple quotes found in value: "/utf8, Value/binary>>}; [] -> {ok, Value} end; {error, _} -> {error, <<"Regex error at extract_within_quotes, this is a bug, please create an issue"/utf8>>} end. -spec normalize_value(binary()) -> {ok, binary()} | {error, binary()}. normalize_value(Value) -> Has_double_quotes = gleam@string:starts_with(Value, <<"\""/utf8>>), gleam@result:'try'( begin _pipe = gleam@string:trim(Value), remove_surrounding_quotes(_pipe) end, fun(Value@1) -> gleam@bool:guard( not Has_double_quotes, {ok, Value@1}, fun() -> {ok, expand_new_lines(Value@1)} end ) end ). -spec is_valid_key(binary()) -> boolean(). is_valid_key(Key) -> case gleam@regex:compile( <<"^[a-zA-Z_]+[a-zA-Z0-9_]*$"/utf8>>, {options, false, true} ) of {ok, Re} -> gleam@regex:check(Re, Key); {error, _} -> false end. -spec to_pairs(list(binary()), list({binary(), binary()})) -> {ok, list({binary(), binary()})} | {error, binary()}. to_pairs(Raw_list, State) -> case Raw_list of [Key, Value | Rest] -> case is_valid_key(Key) of true -> gleam@result:'try'( normalize_value(Value), fun(Normalized_value) -> to_pairs( Rest, gleam@list:concat( [State, [{Key, Normalized_value}]] ) ) end ); false -> to_pairs(Rest, State) end; [Key@1] -> gleam@bool:guard( not is_valid_key(Key@1), {ok, State}, fun() -> {ok, gleam@list:concat([State, [{Key@1, <<""/utf8>>}]])} end ); [] -> {ok, State}; _ -> {ok, State} end. -spec is_comment(binary()) -> boolean(). is_comment(Line) -> case gleam@string:trim(Line) of <<"#"/utf8, _/binary>> -> true; _ -> false end. -spec replace(binary(), binary(), binary()) -> binary(). replace(Str, Regex, With) -> case gleam@regex:compile(Regex, {options, true, true}) of {ok, Re} -> _pipe = gleam@regex:split(Re, Str), _pipe@1 = gleam@string:join(_pipe, With), gleam@string:trim(_pipe@1); {error, _} -> Str end. -spec pop_first_if_empty(gleam@queue:queue(binary())) -> gleam@queue:queue(binary()). pop_first_if_empty(Items) -> case gleam@queue:pop_front(Items) of {ok, {First, _}} -> gleam@bool:guard( First /= <<""/utf8>>, Items, fun() -> case gleam@queue:pop_front(Items) of {ok, {_, Rest}} -> Rest; {error, _} -> Items end end ); {error, _} -> Items end. -spec pop_last_if_empty(gleam@queue:queue(binary())) -> gleam@queue:queue(binary()). pop_last_if_empty(Items) -> case gleam@queue:pop_back(Items) of {ok, {Last, _}} -> gleam@bool:guard( Last /= <<""/utf8>>, Items, fun() -> case gleam@queue:pop_back(Items) of {ok, {_, Rest}} -> Rest; {error, _} -> Items end end ); {error, _} -> Items end. -spec lines_to_list(binary()) -> list(binary()). lines_to_list(Text) -> _pipe = case gleam@regex:compile( <<"(?:^|^)\\s*(?:export\\s+)?([\\w.-]+)(?:\\s*=\\s*?|:\\s+?)(\\s*'(?:\\\\'|[^'])*'|\\s*\"(?:\\\\\"|[^\"])*\"|\\s*`(?:\\\\`|[^`])*`|[^#\\r\\n]+)?\\s*(?:#.*)?(?:$|$)"/utf8>>, {options, true, true} ) of {ok, Re} -> gleam@regex:split(Re, Text); {error, _} -> [] end, gleam@list:filter( _pipe, fun(Line) -> (Line /= <<"\n"/utf8>>) andalso not is_comment(Line) end ). -spec parse(binary()) -> {ok, list({binary(), binary()})} | {error, binary()}. parse(Text) -> Lines = replace(Text, <<"\r\n?"/utf8>>, <<"\n"/utf8>>), gleam@result:'try'( begin _pipe = lines_to_list(Lines), _pipe@1 = gleam@queue:from_list(_pipe), _pipe@2 = pop_first_if_empty(_pipe@1), _pipe@3 = pop_last_if_empty(_pipe@2), _pipe@4 = gleam@queue:to_list(_pipe@3), to_pairs(_pipe@4, []) end, fun(Env_map) -> {ok, Env_map} end ).