Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion lib/bash/cli/lib_cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,7 @@ base_cli_option() {
# Usage: base_cli_positional model command_path name [required=true] [repeatable=true] ...
base_cli_positional() {
local model="${1-}" path="${2-}" name="${3-}" key names
local previous previous_required
local -a __base_bash_libs_cli_previous_positionals=()

if (($# < 3)); then
Expand Down Expand Up @@ -991,12 +992,23 @@ base_cli_positional() {
fi
if [[ -n "$names" ]]; then
IFS=, read -r -a __base_bash_libs_cli_previous_positionals <<< "$names"
local previous="${__base_bash_libs_cli_previous_positionals[${#__base_bash_libs_cli_previous_positionals[@]} - 1]}"
previous="${__base_bash_libs_cli_previous_positionals[${#__base_bash_libs_cli_previous_positionals[@]} - 1]}"
if [[ "$(__base_bash_libs_cli_positional_meta__ "$model" "$path" "$previous" repeatable)" =~ ^(1|true|yes)$ ]]; then
__base_bash_libs_cli_declaration_usage__ "base_cli_positional: cannot declare '$name' after repeatable positional '$previous'."
return 2
fi
fi
if [[ "${__base_bash_libs_cli_attrs[required]-}" =~ ^(1|true|yes)$ && -n "$names" ]]; then
for previous in "${__base_bash_libs_cli_previous_positionals[@]}"; do
previous_required="$(__base_bash_libs_cli_positional_meta__ "$model" "$path" "$previous" required)"
if [[ ! "$previous_required" =~ ^(1|true|yes)$ ||
-n "${__base_bash_libs_cli_models["$model|positional|$path|meta|$previous|default"]+set}" ]]; then
__base_bash_libs_cli_declaration_usage__ \
"base_cli_positional: cannot declare required positional '$name' after optional positional '$previous'."
return 2
fi
done
fi
if [[ -n "$names" ]]; then names="$names,$name"; else names="$name"; fi
__base_bash_libs_cli_models["$model|command|positionals|$path"]="$names"
for key in help metavar default required enum validator repeatable; do
Expand Down
27 changes: 27 additions & 0 deletions lib/bash/cli/tests/lib_cli.bats
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,33 @@ EOF
base_cli_parse optional_repeat -- run target-only
}

@test "required positionals cannot follow optional or defaulted positionals" {
base_cli_model_init ordering name=ordering
base_cli_command ordering run "Run"
base_cli_positional ordering run context

bats_run base_cli_positional ordering run target required=true
[ "$status" -eq 2 ]
[[ "$output" == *"cannot declare required positional 'target' after optional positional 'context'"* ]]
[ "${__base_bash_libs_cli_models[ordering\|command\|positionals\|run]}" = context ]

base_cli_model_init defaulted_order name=defaulted-order
base_cli_command defaulted_order run "Run"
base_cli_positional defaulted_order run context default=working

bats_run base_cli_positional defaulted_order run target required=true
[ "$status" -eq 2 ]
[[ "$output" == *"cannot declare required positional 'target' after optional positional 'context'"* ]]

base_cli_model_init valid_order name=valid-order
base_cli_command valid_order run "Run"
base_cli_positional valid_order run target required=true
base_cli_positional valid_order run context default=working
base_cli_parse valid_order -- run target-value
[ "${BASE_BASH_LIBS_CLI_RESULT_POSITIONALS[0]}" = target-value ]
[ "${BASE_BASH_LIBS_CLI_RESULT_POSITIONALS[1]}" = working ]
}

@test "quick declarations enforce required repeatable positional tails" {
base_cli_declare table_repeat \
'model|name=table-repeat' \
Expand Down
Loading