From 7ab48a653b6e488e93758f2973b50e53272b8dc5 Mon Sep 17 00:00:00 2001 From: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:08:50 +0000 Subject: [PATCH] [Fix] `nvm_print_implicit_alias`: keep `STABLE` bound, and `STABLE` and `UNSTABLE` independent of the caller `STABLE` is only assigned inside the loop over `LAST_TWO`, but it is echoed unconditionally afterwards. With nothing installed, or with only an odd minor, the loop never runs, so under `set -u` `nvm ls` dies on `STABLE: unbound variable` instead of resolving `stable` to nothing. `local STABLE` without an initializer also keeps the caller's value in sh and dash, so `STABLE=x nvm ls stable` resolves the alias to something that isn't installed. Initializing it where it is declared fixes both, the way 139ed9c did for `PATTERN`, `NVM_LTS`, `LTS` and `VERSION`. `local UNSTABLE` keeps the caller's value the same way, which its `N/A` fallback doesn't cover, so it is initialized too. The nounset test now covers the two states that leave `stable` unresolved, and the caller test that `nvm ls stable` answers the same either way, and that an outer `UNSTABLE` doesn't become the `unstable` alias. Co-authored-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com> Co-authored-by: Jordan Harband --- nvm.sh | 2 ++ ...ning 'nvm ls' with nounset should not fail | 20 ++++++++++++++----- ... ignore option variables set by the caller | 15 ++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/nvm.sh b/nvm.sh index db16abe7..58f2704d 100755 --- a/nvm.sh +++ b/nvm.sh @@ -3294,7 +3294,9 @@ nvm_print_implicit_alias() { esac local MINOR local STABLE + STABLE='' local UNSTABLE + UNSTABLE='' local MOD local NORMALIZED_VERSION diff --git a/test/fast/Listing versions/Running 'nvm ls' with nounset should not fail b/test/fast/Listing versions/Running 'nvm ls' with nounset should not fail index f6770917..90f0851d 100755 --- a/test/fast/Listing versions/Running 'nvm ls' with nounset should not fail +++ b/test/fast/Listing versions/Running 'nvm ls' with nounset should not fail @@ -6,19 +6,29 @@ die () { echo "$@" ; exit 1; } \. ../../../nvm.sh \. ../../common.sh -make_fake_node v0.12.34 || die 'fake v0.12.34 could not be made' - # Enable no unset variable set -u +# Nothing is installed, so there is no stable version to resolve to +output=$(nvm ls 2>&1 1>/dev/null || true) +test -z "${output}" || die "1: expected empty; got >${output}" + +make_fake_node v0.11.16 || die 'fake v0.11.16 could not be made' + +# Only an unstable version is installed, so `stable` still has nothing to resolve to +output=$(nvm ls 2>&1 1>/dev/null || true) +test -z "${output}" || die "2: expected empty; got >${output}" + +make_fake_node v0.12.34 || die 'fake v0.12.34 could not be made' + # Try an alias that does not exist output=$(nvm ls 99 2>&1 1>/dev/null || true) -test -z "${output}" || die "1: expected empty; got >${output}" +test -z "${output}" || die "3: expected empty; got >${output}" # Try a version that does not exist output=$(nvm ls 0.12.00 2>&1 1>/dev/null || true) -test -z "${output}" || die "2: expected empty; got >${output}" +test -z "${output}" || die "4: expected empty; got >${output}" # Try a version that does exist output=$(nvm ls 0.12.34 2>&1 1>/dev/null || true) -test -z "${output}" || die "3: expected empty; got >${output}" +test -z "${output}" || die "5: expected empty; got >${output}" diff --git a/test/fast/Unit tests/nvm commands ignore option variables set by the caller b/test/fast/Unit tests/nvm commands ignore option variables set by the caller index 08acd927..517e9daf 100755 --- a/test/fast/Unit tests/nvm commands ignore option variables set by the caller +++ b/test/fast/Unit tests/nvm commands ignore option variables set by the caller @@ -54,4 +54,19 @@ VERSION=v20.0.0 [ $? = 127 ] || die 'nvm use without a version or an .nvmrc should fail, rather than use an outer VERSION' unset VERSION +# with nothing installed, `nvm ls stable` has no version to resolve to, so an outer STABLE must not supply one +NVM_DIR="${TMP_DIR}/empty" +mkdir -p "${NVM_DIR}" +OUTPUT="$(nvm ls stable | tr -d ' \n')" +STABLE=v20.0.0 +OUTPUT_WITH_STABLE="$(nvm ls stable | tr -d ' \n')" +[ "_${OUTPUT_WITH_STABLE}" = "_${OUTPUT}" ] || die "nvm ls stable should ignore an outer STABLE; got >${OUTPUT_WITH_STABLE}< instead of >${OUTPUT}<" +unset STABLE + +# likewise for an outer UNSTABLE; `nvm ls unstable` can't show it, since the leaked version isn't installed either +UNSTABLE=v21.0.0 +OUTPUT="$(nvm_print_implicit_alias local unstable)" +[ "_${OUTPUT}" = '_N/A' ] || die "nvm_print_implicit_alias local unstable should ignore an outer UNSTABLE; got >${OUTPUT}<" +unset UNSTABLE + cleanup