-module(libero@cli@validation). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/libero/cli/validation.gleam"). -export([is_lowercase_letter/1, is_digit/1, validate_name/3]). -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 validation for CLI commands (project names, client names, etc.).\n"). -file("src/libero/cli/validation.gleam", 69). -spec kind_cap(binary()) -> binary(). kind_cap(Kind) -> case Kind of <<"project"/utf8>> -> <<"Project"/utf8>>; <<"client"/utf8>> -> <<"Client"/utf8>>; _ -> Kind end. -file("src/libero/cli/validation.gleam", 10). -spec is_lowercase_letter(binary()) -> boolean(). is_lowercase_letter(Ch) -> gleam_stdlib:contains_string(<<"abcdefghijklmnopqrstuvwxyz"/utf8>>, Ch). -file("src/libero/cli/validation.gleam", 14). -spec is_digit(binary()) -> boolean(). is_digit(Ch) -> gleam_stdlib:contains_string(<<"0123456789"/utf8>>, Ch). -file("src/libero/cli/validation.gleam", 27). ?DOC( " Validate a name for use as a project or client name.\n" " Returns Ok(Nil) if valid, Error(String) with a user-facing error message if not.\n" " nolint: stringly_typed_error -- CLI-facing error, String is appropriate\n" ). -spec validate_name(binary(), binary(), binary()) -> {ok, nil} | {error, binary()}. validate_name(Name, Kind, Hint) -> case gleam@string:to_graphemes(Name) of [] -> {error, <<<<<<<<<<"error: Invalid "/utf8, Kind/binary>>/binary, " name \x{2502} \x{2502} "/utf8>>/binary, (kind_cap(Kind))/binary>>/binary, " name cannot be empty \x{2502} hint: "/utf8>>/binary, Hint/binary>>}; [First | Rest] -> case is_lowercase_letter(First) of false -> {error, <<<<<<<<<<<<"error: Invalid "/utf8, Kind/binary>>/binary, " name: `"/utf8>>/binary, Name/binary>>/binary, "` \x{2502} \x{2502} Must start with a lowercase letter (a-z) \x{2502} hint: Try `"/utf8>>/binary, (string:lowercase(Name))/binary>>/binary, "` instead"/utf8>>}; true -> case gleam@list:all( Rest, fun(Ch) -> (is_lowercase_letter(Ch) orelse is_digit(Ch)) orelse (Ch =:= <<"_"/utf8>>) end ) of false -> {error, <<<<<<<<"error: Invalid "/utf8, Kind/binary>>/binary, " name: `"/utf8>>/binary, Name/binary>>/binary, "` \x{2502} \x{2502} Must contain only lowercase letters, digits, and underscores"/utf8>>}; true -> case gleam@list:contains( [<<"as"/utf8>>, <<"assert"/utf8>>, <<"auto"/utf8>>, <<"case"/utf8>>, <<"const"/utf8>>, <<"external"/utf8>>, <<"fn"/utf8>>, <<"if"/utf8>>, <<"import"/utf8>>, <<"let"/utf8>>, <<"macro"/utf8>>, <<"opaque"/utf8>>, <<"panic"/utf8>>, <<"pub"/utf8>>, <<"test"/utf8>>, <<"todo"/utf8>>, <<"type"/utf8>>, <<"use"/utf8>>], Name ) of true -> {error, <<<<<<<<<<<<"error: Invalid "/utf8, Kind/binary>>/binary, " name: `"/utf8>>/binary, Name/binary>>/binary, "` \x{2502} \x{2502} `"/utf8>>/binary, Name/binary>>/binary, "` is a Gleam reserved word \x{2502} hint: Choose a different name"/utf8>>}; false -> {ok, nil} end end end end.