Skip to main content

src/packkit@error.erl

-module(packkit@error).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/error.gleam").
-export([format_codec_error/1, format_archive_error/1, format_detect_error/1, format_recipe_error/1]).
-export_type([codec_error/0, archive_error/0, recipe_error/0, detect_error/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(
    " Shared public error families for the `packkit` facade and the\n"
    " early scaffold modules.\n"
).

-type codec_error() :: {codec_invalid_data, binary()} |
    {codec_limit_exceeded, binary(), integer()} |
    {codec_dictionary_required, binary()} |
    {codec_dictionary_mismatch, binary()} |
    {codec_option_unsupported, binary(), binary()} |
    {codec_not_implemented, binary()}.

-type archive_error() :: {archive_unsupported, binary()} |
    {archive_invalid, binary()} |
    {archive_entry_rejected, binary(), binary()} |
    {archive_limit_exceeded, binary(), integer()} |
    {archive_not_implemented, binary()} |
    {archive_codec_failed, binary(), codec_error()} |
    {archive_format_mismatch, binary(), binary()} |
    {archive_field_overflow, binary(), integer(), integer()} |
    {archive_comment_unsupported, binary()}.

-type recipe_error() :: {recipe_archive_already_set, binary()} |
    recipe_empty_codec_chain |
    {recipe_unsupported_composition, binary()} |
    {recipe_not_implemented, binary()}.

-type detect_error() :: {detect_unknown_format, binary()} |
    {detect_not_implemented, binary()}.

-file("src/packkit/error.gleam", 70).
?DOC(
    " Format a `CodecError` as a single user-facing line.  Hides the\n"
    " constructor names and field labels that `string.inspect` would\n"
    " expose, so the output is suitable for CLI error reporting.\n"
).
-spec format_codec_error(codec_error()) -> binary().
format_codec_error(Err) ->
    case Err of
        {codec_invalid_data, Message} ->
            <<"codec: invalid data — "/utf8, Message/binary>>;

        {codec_limit_exceeded, Limit, Actual} ->
            <<<<<<<<"codec: limit \""/utf8, Limit/binary>>/binary,
                        "\" exceeded (actual="/utf8>>/binary,
                    (erlang:integer_to_binary(Actual))/binary>>/binary,
                ")"/utf8>>;

        {codec_dictionary_required, Name} ->
            <<<<"codec: "/utf8, Name/binary>>/binary,
                " requires a preset dictionary"/utf8>>;

        {codec_dictionary_mismatch, Name@1} ->
            <<<<"codec: "/utf8, Name@1/binary>>/binary,
                " preset-dictionary id mismatch"/utf8>>;

        {codec_option_unsupported, Option, Codec_name} ->
            <<<<<<<<"codec: "/utf8, Codec_name/binary>>/binary,
                        " does not support the requested option \""/utf8>>/binary,
                    Option/binary>>/binary,
                "\""/utf8>>;

        {codec_not_implemented, Feature} ->
            <<"codec: not yet implemented — "/utf8, Feature/binary>>
    end.

-file("src/packkit/error.gleam", 96).
?DOC(
    " Format an `ArchiveError` as a single user-facing line.  Nested\n"
    " `CodecError` (under `ArchiveCodecFailed`) is rendered through\n"
    " `format_codec_error` so the user sees one continuous sentence.\n"
).
-spec format_archive_error(archive_error()) -> binary().
format_archive_error(Err) ->
    case Err of
        {archive_unsupported, Name} ->
            <<<<"archive: unsupported format \""/utf8, Name/binary>>/binary,
                "\""/utf8>>;

        {archive_invalid, Message} ->
            <<"archive: invalid — "/utf8, Message/binary>>;

        {archive_entry_rejected, Path, Reason} ->
            <<<<<<"archive: entry \""/utf8, Path/binary>>/binary,
                    "\" rejected — "/utf8>>/binary,
                Reason/binary>>;

        {archive_limit_exceeded, Limit, Actual} ->
            <<<<<<<<"archive: limit \""/utf8, Limit/binary>>/binary,
                        "\" exceeded (actual="/utf8>>/binary,
                    (erlang:integer_to_binary(Actual))/binary>>/binary,
                ")"/utf8>>;

        {archive_not_implemented, Feature} ->
            <<"archive: not yet implemented — "/utf8, Feature/binary>>;

        {archive_codec_failed, Step, Cause} ->
            <<<<<<"archive: "/utf8, Step/binary>>/binary, " step — "/utf8>>/binary,
                (format_codec_error(Cause))/binary>>;

        {archive_format_mismatch, Archive, Requested} ->
            <<<<<<<<"archive: format mismatch (archive was built as \""/utf8,
                            Archive/binary>>/binary,
                        "\" but \""/utf8>>/binary,
                    Requested/binary>>/binary,
                "\" was requested)"/utf8>>;

        {archive_field_overflow, Field, Value, Max} ->
            <<<<<<<<<<<<"archive: field \""/utf8, Field/binary>>/binary,
                                "\" overflow (value="/utf8>>/binary,
                            (erlang:integer_to_binary(Value))/binary>>/binary,
                        ", max="/utf8>>/binary,
                    (erlang:integer_to_binary(Max))/binary>>/binary,
                ")"/utf8>>;

        {archive_comment_unsupported, Format} ->
            <<<<"archive: format \""/utf8, Format/binary>>/binary,
                "\" does not carry archive comments"/utf8>>
    end.

-file("src/packkit/error.gleam", 132).
?DOC(" Format a `DetectError` as a single user-facing line.\n").
-spec format_detect_error(detect_error()) -> binary().
format_detect_error(Err) ->
    case Err of
        {detect_unknown_format, Input} ->
            <<<<"detect: could not classify input \""/utf8, Input/binary>>/binary,
                "\""/utf8>>;

        {detect_not_implemented, Feature} ->
            <<"detect: not yet implemented — "/utf8, Feature/binary>>
    end.

-file("src/packkit/error.gleam", 141).
?DOC(" Format a `RecipeError` as a single user-facing line.\n").
-spec format_recipe_error(recipe_error()) -> binary().
format_recipe_error(Err) ->
    case Err of
        {recipe_archive_already_set, Current} ->
            <<<<"recipe: archive layer is already set to \""/utf8,
                    Current/binary>>/binary,
                "\""/utf8>>;

        recipe_empty_codec_chain ->
            <<"recipe: codec chain is empty"/utf8>>;

        {recipe_unsupported_composition, Description} ->
            <<"recipe: unsupported composition — "/utf8, Description/binary>>;

        {recipe_not_implemented, Feature} ->
            <<"recipe: not yet implemented — "/utf8, Feature/binary>>
    end.