-module(acumen@internal@link_header). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/acumen/internal/link_header.gleam"). -export([find_by_rel/2]). -export_type([link_header/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(false). -type link_header() :: {link_header, acumen@url:url(), list({binary(), binary()})}. -file("src/acumen/internal/link_header.gleam", 18). ?DOC(false). -spec has_rel(list({binary(), binary()}), binary()) -> boolean(). has_rel(Parameters, Rel) -> gleam@list:any( Parameters, fun(Param) -> (erlang:element(1, Param) =:= <<"rel"/utf8>>) andalso gleam@list:contains( gleam@string:split(erlang:element(2, Param), <<" "/utf8>>), Rel ) end ). -file("src/acumen/internal/link_header.gleam", 210). ?DOC(false). -spec parse_quoted_value(binary(), binary(), binary()) -> {ok, {{binary(), binary()}, binary()}} | {error, nil}. parse_quoted_value(Header, Name, Value) -> case gleam_stdlib:string_pop_grapheme(Header) of {error, nil} -> {error, nil}; {ok, {<<"\""/utf8>>, Rest}} -> {ok, {{Name, Value}, Rest}}; {ok, {<<"\\"/utf8>>, Rest@1}} -> case gleam_stdlib:string_pop_grapheme(Rest@1) of {error, nil} -> {error, nil}; {ok, {Grapheme, Rest@2}} -> parse_quoted_value( Rest@2, Name, <> ) end; {ok, {Grapheme@1, Rest@3}} -> parse_quoted_value( Rest@3, Name, <> ) end. -file("src/acumen/internal/link_header.gleam", 229). ?DOC(false). -spec parse_unquoted_value(binary(), binary(), binary()) -> {{binary(), binary()}, binary()}. parse_unquoted_value(Header, Name, Value) -> case Header of <<""/utf8>> -> {{Name, Value}, Header}; <<";"/utf8, _/binary>> -> {{Name, Value}, Header}; <<" "/utf8, Rest/binary>> -> {{Name, Value}, Rest}; <<"\t"/utf8, Rest/binary>> -> {{Name, Value}, Rest}; _ -> case gleam_stdlib:string_pop_grapheme(Header) of {error, _} -> {{Name, Value}, <<""/utf8>>}; {ok, {Grapheme, Rest@1}} -> parse_unquoted_value( Rest@1, Name, <> ) end end. -file("src/acumen/internal/link_header.gleam", 194). ?DOC(false). -spec parse_parameter_value(binary(), binary()) -> {ok, {{binary(), binary()}, binary()}} | {error, nil}. parse_parameter_value(Header, Name) -> case Header of <<""/utf8>> -> {error, nil}; <<"\""/utf8, Rest/binary>> -> parse_quoted_value(Rest, Name, <<""/utf8>>); _ -> case gleam_stdlib:string_pop_grapheme(Header) of {error, _} -> {error, nil}; {ok, {Grapheme, Rest@1}} -> {ok, parse_unquoted_value(Rest@1, Name, Grapheme)} end end. -file("src/acumen/internal/link_header.gleam", 183). ?DOC(false). -spec parse_link_parameter_after_name(binary(), binary()) -> {ok, {{binary(), binary()}, binary()}} | {error, nil}. parse_link_parameter_after_name(Header, Name) -> case Header of <<""/utf8>> -> {ok, {{Name, <<""/utf8>>}, <<""/utf8>>}}; <<"="/utf8, Rest/binary>> -> parse_parameter_value(gleam@string:trim_start(Rest), Name); _ -> {ok, {{Name, <<""/utf8>>}, Header}} end. -file("src/acumen/internal/link_header.gleam", 156). ?DOC(false). -spec parse_link_parameter_name(binary(), binary()) -> {ok, {{binary(), binary()}, binary()}} | {error, nil}. parse_link_parameter_name(Header, Name) -> Sep = splitter:new( [<<"="/utf8>>, <<" "/utf8>>, <<"\t"/utf8>>, <<";"/utf8>>] ), case splitter_ffi:split(Sep, Header) of {Prefix, <<""/utf8>>, <<""/utf8>>} -> {ok, {{<>, <<""/utf8>>}, <<""/utf8>>}}; {Prefix@1, <<"="/utf8>>, Rest} -> parse_parameter_value( gleam@string:trim_start(Rest), <> ); {Prefix@2, <<" "/utf8>>, Rest@1} -> parse_link_parameter_after_name( gleam@string:trim_start(Rest@1), <> ); {Prefix@2, <<"\t"/utf8>>, Rest@1} -> parse_link_parameter_after_name( gleam@string:trim_start(Rest@1), <> ); {Prefix@3, <<";"/utf8>>, Rest@2} -> {ok, {{<>, <<""/utf8>>}, <<";"/utf8, Rest@2/binary>>}}; {Prefix@4, _, Rest@3} -> {ok, {{<>, <<""/utf8>>}, Rest@3}} end. -file("src/acumen/internal/link_header.gleam", 130). ?DOC(false). -spec parse_link_parameters_after_semicolon( binary(), list({binary(), binary()}) ) -> {ok, list({binary(), binary()})} | {error, nil}. parse_link_parameters_after_semicolon(Header, Parameters) -> case Header of <<""/utf8>> -> {error, nil}; <<" "/utf8, Rest/binary>> -> parse_link_parameters_after_semicolon(Rest, Parameters); <<"\t"/utf8, Rest/binary>> -> parse_link_parameters_after_semicolon(Rest, Parameters); _ -> case gleam_stdlib:string_pop_grapheme(Header) of {error, _} -> {error, nil}; {ok, {Grapheme, Rest@1}} -> Name = string:lowercase(Grapheme), gleam@result:'try'( parse_link_parameter_name(Rest@1, Name), fun(_use0) -> {Parameter, Rest@2} = _use0, parse_link_parameters( Rest@2, [Parameter | Parameters] ) end ) end end. -file("src/acumen/internal/link_header.gleam", 115). ?DOC(false). -spec parse_link_parameters(binary(), list({binary(), binary()})) -> {ok, list({binary(), binary()})} | {error, nil}. parse_link_parameters(Header, Parameters) -> case Header of <<""/utf8>> -> {ok, lists:reverse(Parameters)}; <<" "/utf8, Rest/binary>> -> parse_link_parameters(Rest, Parameters); <<"\t"/utf8, Rest/binary>> -> parse_link_parameters(Rest, Parameters); <<";"/utf8, Rest@1/binary>> -> parse_link_parameters_after_semicolon(Rest@1, Parameters); _ -> {error, nil} end. -file("src/acumen/internal/link_header.gleam", 102). ?DOC(false). -spec parse_link_value(binary()) -> {ok, link_header()} | {error, nil}. parse_link_value(Link_value) -> case gleam@string:trim_start(Link_value) of <<"<"/utf8, After_open/binary>> -> gleam@result:'try'( gleam@string:split_once(After_open, <<">"/utf8>>), fun(_use0) -> {Uri_string, Params} = _use0, gleam@result:'try'( acumen@url:from_string(Uri_string), fun(Parsed_url) -> _pipe = parse_link_parameters(Params, []), gleam@result:map( _pipe, fun(_capture) -> {link_header, Parsed_url, _capture} end ) end ) end ); _ -> {error, nil} end. -file("src/acumen/internal/link_header.gleam", 49). ?DOC(false). -spec find_link_separator( splitter:splitter(), binary(), binary(), list(binary()), boolean() ) -> list(binary()). find_link_separator(Sep, Remaining, Current, Acc, In_quote) -> case splitter_ffi:split(Sep, Remaining) of {Rest, <<""/utf8>>, <<""/utf8>>} -> case gleam@string:trim(<>) of <<""/utf8>> -> lists:reverse(Acc); Trimmed -> lists:reverse([Trimmed | Acc]) end; {Before, <<"\\"/utf8>>, Rest@1} when In_quote -> case gleam_stdlib:string_pop_grapheme(Rest@1) of {ok, {Escaped, Rest@2}} -> find_link_separator( Sep, Rest@2, <<<<<>/binary, "\\"/utf8>>/binary, Escaped/binary>>, Acc, In_quote ); {error, _} -> find_link_separator( Sep, Rest@1, <<<>/binary, "\\"/utf8>>, Acc, In_quote ) end; {Before@1, <<"\\"/utf8>>, Rest@3} -> find_link_separator( Sep, Rest@3, <<<>/binary, "\\"/utf8>>, Acc, In_quote ); {Before@2, <<"\""/utf8>>, Rest@4} -> find_link_separator( Sep, Rest@4, <<<>/binary, "\""/utf8>>, Acc, not In_quote ); {Before@3, <<","/utf8>>, Rest@5} when In_quote -> find_link_separator( Sep, Rest@5, <<<>/binary, ","/utf8>>, Acc, In_quote ); {Before@4, <<","/utf8>>, Rest@6} -> split_link_values( Sep, Rest@6, [gleam@string:trim(<>) | Acc] ); {Before@5, Delim, Rest@7} -> find_link_separator( Sep, Rest@7, <<<>/binary, Delim/binary>>, Acc, In_quote ) end. -file("src/acumen/internal/link_header.gleam", 31). ?DOC(false). -spec split_link_values(splitter:splitter(), binary(), list(binary())) -> list(binary()). split_link_values(Sep, Remaining, Acc) -> case gleam@string:trim(Remaining) of <<""/utf8>> -> lists:reverse(Acc); <<","/utf8, Rest/binary>> -> split_link_values(Sep, Rest, Acc); Trimmed -> case gleam@string:split_once(Trimmed, <<">"/utf8>>) of {error, _} -> lists:reverse([Trimmed | Acc]); {ok, {Before_close, After_close}} -> find_link_separator( Sep, After_close, <"/utf8>>, Acc, false ) end end. -file("src/acumen/internal/link_header.gleam", 24). ?DOC(false). -spec parse_link_header(binary()) -> {ok, list(link_header())} | {error, nil}. parse_link_header(Header) -> Sep = splitter:new([<<","/utf8>>, <<"\""/utf8>>, <<"\\"/utf8>>]), _pipe = Header, _pipe@1 = split_link_values(Sep, _pipe, []), gleam@list:try_map(_pipe@1, fun parse_link_value/1). -file("src/acumen/internal/link_header.gleam", 11). ?DOC(false). -spec find_by_rel(binary(), binary()) -> {ok, acumen@url:url()} | {error, nil}. find_by_rel(Header, Rel) -> gleam@result:'try'(parse_link_header(Header), fun(Links) -> _pipe = Links, _pipe@1 = gleam@list:find( _pipe, fun(Link) -> has_rel(erlang:element(3, Link), Rel) end ), gleam@result:map( _pipe@1, fun(Link@1) -> erlang:element(2, Link@1) end ) end).