Current section

Files

Jump to
dot_env src dot_env@internal@parser.erl
Raw

src/dot_env@internal@parser.erl

-module(dot_env@internal@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
-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) -> _pipe@1 = case Has_double_quotes of
true ->
expand_new_lines(Value@1);
false ->
Value@1
end,
{ok, _pipe@1} 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 ->
case normalize_value(Value) of
{ok, Normalized_value} ->
to_pairs(
Rest,
gleam@list:concat(
[State, [{Key, Normalized_value}]]
)
);
{error, E} ->
{error, E}
end;
false ->
to_pairs(Rest, State)
end;
[Key@1] ->
case is_valid_key(Key@1) of
true ->
{ok, gleam@list:concat([State, [{Key@1, <<""/utf8>>}]])};
false ->
{ok, State}
end;
[] ->
{ok, State};
_ ->
{ok, State}
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>> 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 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
).