-module(html_parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([get_attrs/1, get_first_element/1, as_list/1, as_tree/1]). -export_type([element/0, attribute/0, current_element_type/0]). -type element() :: empty_element | {start_element, binary(), list(attribute()), list(element())} | {end_element, binary()} | {content, binary()}. -type attribute() :: {attribute, binary(), binary()}. -type current_element_type() :: start | 'end' | none. -spec trim_space_to_elem_begin(binary()) -> binary(). trim_space_to_elem_begin(In) -> case In of <<" "/utf8, Remain/binary>> -> trim_space_to_elem_begin(Remain); <<"\n"/utf8, Remain/binary>> -> trim_space_to_elem_begin(Remain); <<"\t"/utf8, Remain/binary>> -> trim_space_to_elem_begin(Remain); <<"<"/utf8, Remain@1/binary>> -> <<"<"/utf8, Remain@1/binary>>; _ -> In end. -spec remove_quotes(binary()) -> binary(). remove_quotes(In) -> Remove_first_quote = fun(Str) -> case Str of <<"\""/utf8, Remain/binary>> -> Remain; _ -> Str end end, _pipe = In, _pipe@1 = Remove_first_quote(_pipe), _pipe@2 = gleam@string:reverse(_pipe@1), _pipe@3 = Remove_first_quote(_pipe@2), gleam@string:reverse(_pipe@3). -spec do_get_attrs(binary(), binary(), binary(), boolean()) -> {list(attribute()), binary()}. do_get_attrs(In, Key, Val, Finding_value) -> case In of <<""/utf8>> -> case {Key, Val} of {<<""/utf8>>, <<""/utf8>>} -> {[], <<""/utf8>>}; {_, <<""/utf8>>} -> {[], Key}; {_, _} -> {[{attribute, Key, remove_quotes(Val)}], <<""/utf8>>} end; <<">"/utf8>> -> case {Key, Val} of {<<""/utf8>>, <<""/utf8>>} -> {[], <<""/utf8>>}; {_, <<""/utf8>>} -> {[], Key}; {_, _} -> {[{attribute, Key, remove_quotes(Val)}], <<""/utf8>>} end; <<">"/utf8, Remain/binary>> -> case {Key, Val} of {<<""/utf8>>, <<""/utf8>>} -> {[], Remain}; {_, _} -> {[{attribute, Key, remove_quotes(Val)}], Remain} end; <<" "/utf8, Remain@1/binary>> when not Finding_value -> do_get_attrs(Remain@1, Key, Val, Finding_value); <<"\n"/utf8, Remain@1/binary>> when not Finding_value -> do_get_attrs(Remain@1, Key, Val, Finding_value); <<"\t"/utf8, Remain@1/binary>> when not Finding_value -> do_get_attrs(Remain@1, Key, Val, Finding_value); <<" "/utf8, Remain@2/binary>> -> {Attrs, Remain_after_attr} = do_get_attrs( Remain@2, <<""/utf8>>, <<""/utf8>>, false ), {[{attribute, Key, remove_quotes(Val)} | Attrs], Remain_after_attr}; <<"\n"/utf8, Remain@2/binary>> -> {Attrs, Remain_after_attr} = do_get_attrs( Remain@2, <<""/utf8>>, <<""/utf8>>, false ), {[{attribute, Key, remove_quotes(Val)} | Attrs], Remain_after_attr}; <<"\t"/utf8, Remain@2/binary>> -> {Attrs, Remain_after_attr} = do_get_attrs( Remain@2, <<""/utf8>>, <<""/utf8>>, false ), {[{attribute, Key, remove_quotes(Val)} | Attrs], Remain_after_attr}; <<"="/utf8, Remain@3/binary>> -> do_get_attrs(Remain@3, Key, <<""/utf8>>, true); _ -> _assert_subject = gleam@string:pop_grapheme(In), {ok, {Head, Remain@4}} = case _assert_subject of {ok, {_, _}} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"html_parser"/utf8>>, function => <<"do_get_attrs"/utf8>>, line => 120}) end, case Finding_value of true -> do_get_attrs( Remain@4, Key, <>, Finding_value ); false -> do_get_attrs( Remain@4, <>, <<""/utf8>>, Finding_value ) end end. -spec get_attrs(binary()) -> {list(attribute()), binary()}. get_attrs(In) -> _pipe = In, _pipe@1 = trim_space_to_elem_begin(_pipe), do_get_attrs(_pipe@1, <<""/utf8>>, <<""/utf8>>, false). -spec do_get_first_element(binary(), binary(), current_element_type()) -> {element(), binary()}. do_get_first_element(In, Out, Currently_parsing) -> case In of <<"> -> case Out of <<""/utf8>> -> do_get_first_element(Remain, Out, 'end'); _ -> {{content, Out}, <<">} end; <<"<"/utf8, Remain@1/binary>> -> case Out of <<""/utf8>> -> do_get_first_element(Remain@1, Out, start); _ -> {{content, Out}, <<"<"/utf8, Remain@1/binary>>} end; <<">"/utf8, Remain@2/binary>> -> case Currently_parsing of start -> {{start_element, Out, [], []}, Remain@2}; 'end' -> {{end_element, Out}, Remain@2}; none -> {{content, Out}, Remain@2} end; <<" "/utf8, Remain@3/binary>> when Currently_parsing =:= start -> {Attrs, Remain_after_attr} = get_attrs(Remain@3), {{start_element, Out, Attrs, []}, Remain_after_attr}; <<"\n"/utf8, Remain@3/binary>> when Currently_parsing =:= start -> {Attrs, Remain_after_attr} = get_attrs(Remain@3), {{start_element, Out, Attrs, []}, Remain_after_attr}; <<"\t"/utf8, Remain@3/binary>> when Currently_parsing =:= start -> {Attrs, Remain_after_attr} = get_attrs(Remain@3), {{start_element, Out, Attrs, []}, Remain_after_attr}; <<""/utf8>> -> {empty_element, <<""/utf8>>}; _ -> _assert_subject = gleam@string:pop_grapheme(In), {ok, {Head, Remain@4}} = case _assert_subject of {ok, {_, _}} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"html_parser"/utf8>>, function => <<"do_get_first_element"/utf8>>, line => 81}) end, do_get_first_element( Remain@4, <>, Currently_parsing ) end. -spec get_first_element(binary()) -> {element(), binary()}. get_first_element(In) -> _pipe = In, _pipe@1 = trim_space_to_elem_begin(_pipe), do_get_first_element(_pipe@1, <<""/utf8>>, none). -spec as_list(binary()) -> list(element()). as_list(In) -> case In of <<""/utf8>> -> []; _ -> {First, Remain} = get_first_element(In), [First | as_list(Remain)] end. -spec do_as_tree(binary(), element()) -> {element(), binary()}. do_as_tree(In, Current) -> {Next, Remain} = get_first_element(In), {start_element, Cur_name, Cur_attrs, Cur_children} = case Current of {start_element, _, _, _} -> Current; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"html_parser"/utf8>>, function => <<"do_as_tree"/utf8>>, line => 164}) end, case Next of {end_element, Name} when Name =:= Cur_name -> {{start_element, Cur_name, Cur_attrs, begin _pipe = Cur_children, lists:reverse(_pipe) end}, Remain}; {end_element, _} -> do_as_tree(Remain, Current); _ -> {Child_tree, Remain_after_child} = do_as_tree(Remain, Next), do_as_tree( Remain_after_child, {start_element, Cur_name, Cur_attrs, [Child_tree | Cur_children]} ) end. -spec as_tree(binary()) -> element(). as_tree(In) -> {First, Remain} = get_first_element(In), {Result, _} = do_as_tree(Remain, First), Result.