-module(gleeam_code@internal@leetcode).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleeam_code/internal/leetcode.gleam").
-export([describe_error/1, fetch_problem/2, resolve_slug/2]).
-export_type([problem/0, fetch_error/0, snippet/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 problem() :: {problem,
binary(),
binary(),
binary(),
binary(),
binary(),
boolean(),
binary(),
list(binary())}.
-type fetch_error() :: {http_error, binary()} |
{json_error, binary()} |
premium_no_auth |
premium_no_access |
no_content |
no_erlang_snippet |
problem_not_found.
-type snippet() :: {snippet, binary(), binary()}.
-file("src/gleeam_code/internal/leetcode.gleam", 35).
?DOC(false).
-spec describe_error(fetch_error()) -> binary().
describe_error(Err) ->
case Err of
{http_error, Msg} ->
<<"HTTP error: "/utf8, Msg/binary>>;
{json_error, Msg@1} ->
<<"JSON parse error: "/utf8, Msg@1/binary>>;
premium_no_auth ->
<<"Premium problem. Run 'glc auth' to authenticate."/utf8>>;
premium_no_access ->
<<"Premium problem. Your account may not have Premium access."/utf8>>;
no_content ->
<<"Failed to fetch problem content."/utf8>>;
no_erlang_snippet ->
<<"No Erlang code snippet available for this problem."/utf8>>;
problem_not_found ->
<<"Problem not found."/utf8>>
end.
-file("src/gleeam_code/internal/leetcode.gleam", 84).
?DOC(false).
-spec send_graphql(binary(), {ok, binary()} | {error, binary()}) -> {ok,
binary()} |
{error, fetch_error()}.
send_graphql(Body, Session) ->
Base_req = begin
_pipe = gleam@http@request:new(),
_pipe@1 = gleam@http@request:set_method(_pipe, post),
_pipe@2 = gleam@http@request:set_host(_pipe@1, <<"leetcode.com"/utf8>>),
_pipe@3 = gleam@http@request:set_path(_pipe@2, <<"/graphql"/utf8>>),
_pipe@4 = gleam@http@request:set_scheme(_pipe@3, https),
_pipe@5 = gleam@http@request:set_body(_pipe@4, Body),
gleam@http@request:prepend_header(
_pipe@5,
<<"content-type"/utf8>>,
<<"application/json"/utf8>>
)
end,
Req = case Session of
{ok, Cookie} ->
_pipe@6 = Base_req,
gleam@http@request:prepend_header(
_pipe@6,
<<"cookie"/utf8>>,
<<"LEETCODE_SESSION="/utf8, Cookie/binary>>
);
{error, _} ->
Base_req
end,
case gleam@httpc:send(Req) of
{ok, Resp} ->
case erlang:element(2, Resp) of
200 ->
{ok, erlang:element(4, Resp)};
Status ->
{error,
{http_error,
<<"status "/utf8,
(gleam@string:inspect(Status))/binary>>}}
end;
{error, _} ->
{error, {http_error, <<"failed to connect"/utf8>>}}
end.
-file("src/gleeam_code/internal/leetcode.gleam", 208).
?DOC(false).
-spec snippet_decoder() -> gleam@dynamic@decode:decoder(snippet()).
snippet_decoder() ->
gleam@dynamic@decode:field(
<<"langSlug"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Lang_slug) ->
gleam@dynamic@decode:field(
<<"code"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Code) ->
gleam@dynamic@decode:success({snippet, Lang_slug, Code})
end
)
end
).
-file("src/gleeam_code/internal/leetcode.gleam", 214).
?DOC(false).
-spec find_erlang_snippet(list(snippet())) -> {ok, binary()} |
{error, fetch_error()}.
find_erlang_snippet(Snippets) ->
case gleam@list:find(
Snippets,
fun(S) -> erlang:element(2, S) =:= <<"erlang"/utf8>> end
) of
{ok, Snippet} ->
{ok, erlang:element(3, Snippet)};
{error, _} ->
{error, no_erlang_snippet}
end.
-file("src/gleeam_code/internal/leetcode.gleam", 155).
?DOC(false).
-spec parse_full_problem(binary(), binary()) -> {ok, problem()} |
{error, fetch_error()}.
parse_full_problem(Body, Content) ->
Decoder = gleam@dynamic@decode:at(
[<<"data"/utf8>>, <<"question"/utf8>>],
begin
gleam@dynamic@decode:field(
<<"questionFrontendId"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Frontend_id) ->
gleam@dynamic@decode:field(
<<"titleSlug"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Title_slug) ->
gleam@dynamic@decode:field(
<<"title"/utf8>>,
{decoder,
fun gleam@dynamic@decode:decode_string/1},
fun(Title) ->
gleam@dynamic@decode:field(
<<"difficulty"/utf8>>,
{decoder,
fun gleam@dynamic@decode:decode_string/1},
fun(Difficulty) ->
gleam@dynamic@decode:field(
<<"codeSnippets"/utf8>>,
gleam@dynamic@decode:list(
snippet_decoder()
),
fun(Snippets) ->
gleam@dynamic@decode:field(
<<"exampleTestcaseList"/utf8>>,
gleam@dynamic@decode:list(
{decoder,
fun gleam@dynamic@decode:decode_string/1}
),
fun(Testcases) ->
gleam@dynamic@decode:success(
{Frontend_id,
Title_slug,
Title,
Difficulty,
Snippets,
Testcases}
)
end
)
end
)
end
)
end
)
end
)
end
)
end
),
case gleam@json:parse(Body, Decoder) of
{error, _} ->
{error, {json_error, <<"failed to parse problem fields"/utf8>>}};
{ok,
{Frontend_id@1,
Title_slug@1,
Title@1,
Difficulty@1,
Snippets@1,
Testcases@1}} ->
case find_erlang_snippet(Snippets@1) of
{error, Err} ->
{error, Err};
{ok, Erlang_code} ->
{ok,
{problem,
Frontend_id@1,
Title_slug@1,
Title@1,
Difficulty@1,
Content,
false,
Erlang_code,
Testcases@1}}
end
end.
-file("src/gleeam_code/internal/leetcode.gleam", 131).
?DOC(false).
-spec parse_question_fields(binary(), {ok, binary()} | {error, binary()}) -> {ok,
problem()} |
{error, fetch_error()}.
parse_question_fields(Body, Session) ->
Content_decoder = gleam@dynamic@decode:at(
[<<"data"/utf8>>, <<"question"/utf8>>, <<"content"/utf8>>],
gleam@dynamic@decode:optional(
{decoder, fun gleam@dynamic@decode:decode_string/1}
)
),
Is_paid_decoder = gleam@dynamic@decode:at(
[<<"data"/utf8>>, <<"question"/utf8>>, <<"isPaidOnly"/utf8>>],
{decoder, fun gleam@dynamic@decode:decode_bool/1}
),
Content_result = gleam@json:parse(Body, Content_decoder),
Is_paid_result = gleam@json:parse(Body, Is_paid_decoder),
case {Content_result, Is_paid_result} of
{{ok, none}, {ok, true}} ->
case Session of
{ok, _} ->
{error, premium_no_access};
{error, _} ->
{error, premium_no_auth}
end;
{{ok, none}, _} ->
{error, no_content};
{{ok, {some, Content}}, _} ->
parse_full_problem(Body, Content);
{_, _} ->
{error, {json_error, <<"failed to parse content fields"/utf8>>}}
end.
-file("src/gleeam_code/internal/leetcode.gleam", 114).
?DOC(false).
-spec parse_problem_response(binary(), {ok, binary()} | {error, binary()}) -> {ok,
problem()} |
{error, fetch_error()}.
parse_problem_response(Body, Session) ->
Question_decoder = gleam@dynamic@decode:at(
[<<"data"/utf8>>, <<"question"/utf8>>],
gleam@dynamic@decode:optional(gleam@dynamic@decode:success(nil))
),
case gleam@json:parse(Body, Question_decoder) of
{error, _} ->
{error, {json_error, <<"invalid response structure"/utf8>>}};
{ok, Option} ->
case Option of
none ->
{error, problem_not_found};
{some, _} ->
parse_question_fields(Body, Session)
end
end.
-file("src/gleeam_code/internal/leetcode.gleam", 48).
?DOC(false).
-spec fetch_problem(binary(), {ok, binary()} | {error, binary()}) -> {ok,
problem()} |
{error, fetch_error()}.
fetch_problem(Slug, Session) ->
Query = <<<<"{\"query\":\"query questionContent($titleSlug: String!) { question(titleSlug: $titleSlug) { questionFrontendId titleSlug title difficulty content isPaidOnly codeSnippets { lang langSlug code } exampleTestcaseList }}\",\"variables\":{\"titleSlug\":\""/utf8,
Slug/binary>>/binary,
"\"}}"/utf8>>,
gleam@result:'try'(
send_graphql(Query, Session),
fun(Resp) -> parse_problem_response(Resp, Session) end
).
-file("src/gleeam_code/internal/leetcode.gleam", 221).
?DOC(false).
-spec parse_slug_response(binary(), binary()) -> {ok, binary()} |
{error, fetch_error()}.
parse_slug_response(Body, Number) ->
Decoder = gleam@dynamic@decode:at(
[<<"data"/utf8>>, <<"questionList"/utf8>>, <<"data"/utf8>>],
gleam@dynamic@decode:list(
begin
gleam@dynamic@decode:field(
<<"questionFrontendId"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Fid) ->
gleam@dynamic@decode:field(
<<"titleSlug"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Slug) ->
gleam@dynamic@decode:success({Fid, Slug})
end
)
end
)
end
)
),
case gleam@json:parse(Body, Decoder) of
{error, _} ->
{error, {json_error, <<"failed to parse question list"/utf8>>}};
{ok, Items} ->
case gleam@list:find(
Items,
fun(Item) -> erlang:element(1, Item) =:= Number end
) of
{ok, {_, Slug@1}} ->
{ok, Slug@1};
{error, _} ->
{error, problem_not_found}
end
end.
-file("src/gleeam_code/internal/leetcode.gleam", 71).
?DOC(false).
-spec lookup_slug_by_number(binary(), {ok, binary()} | {error, binary()}) -> {ok,
binary()} |
{error, fetch_error()}.
lookup_slug_by_number(Number, Session) ->
Query = <<<<"{\"query\":\"query questionByNumber { questionList: questionList(categorySlug: \\\"\\\" limit: 1 skip: 0 filters: { searchKeywords: \\\""/utf8,
Number/binary>>/binary,
"\\\" }) { data { questionFrontendId titleSlug } }}\"}"/utf8>>,
gleam@result:'try'(
send_graphql(Query, Session),
fun(Resp) -> parse_slug_response(Resp, Number) end
).
-file("src/gleeam_code/internal/leetcode.gleam", 61).
?DOC(false).
-spec resolve_slug(binary(), {ok, binary()} | {error, binary()}) -> {ok,
binary()} |
{error, fetch_error()}.
resolve_slug(Input, Session) ->
case gleeam_code@internal@resolver:is_numeric(Input) of
false ->
{ok, Input};
true ->
lookup_slug_by_number(Input, Session)
end.