|
| 1 | +# nvm Copilot Instructions |
| 2 | + |
| 3 | +This document provides guidance for GitHub Copilot when working with the Node Version Manager (nvm) codebase. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +nvm is a version manager for Node.js, implemented as a POSIX-compliant function that works across multiple shells (sh, dash, bash, ksh, zsh). The codebase is primarily written in shell script and emphasizes portability and compatibility. |
| 8 | + |
| 9 | +### Core Architecture |
| 10 | + |
| 11 | +- **Main script**: `nvm.sh` - Contains all core functionality and the main `nvm()` function |
| 12 | +- **Installation script**: `install.sh` - Handles downloading and installing nvm itself |
| 13 | +- **Execution wrapper**: `nvm-exec` - Allows running commands with specific Node.js versions |
| 14 | +- **Bash completion**: `bash_completion` - Provides tab completion for bash users |
| 15 | +- **Tests**: Comprehensive test suite in `test/` directory using the urchin test framework |
| 16 | + |
| 17 | +## Key Files and Their Purposes |
| 18 | + |
| 19 | +### `nvm.sh` |
| 20 | +The core functionality file containing: |
| 21 | +- Main `nvm()` function (starts around line 3000) |
| 22 | +- All internal helper functions (prefixed with `nvm_`) |
| 23 | +- Command implementations for install, use, ls, etc. |
| 24 | +- Shell compatibility logic |
| 25 | +- POSIX compliance utilities |
| 26 | + |
| 27 | +### `install.sh` |
| 28 | +Handles nvm installation via curl/wget: |
| 29 | +- Downloads nvm from GitHub |
| 30 | +- Sets up directory structure |
| 31 | +- Configures shell integration |
| 32 | +- Supports both git clone and script download methods |
| 33 | + |
| 34 | +### `nvm-exec` |
| 35 | +Simple wrapper script that: |
| 36 | +- Sources nvm.sh with `--no-use` flag |
| 37 | +- Switches to specified Node version via `NODE_VERSION` env var or `.nvmrc` |
| 38 | +- Executes the provided command with that Node version |
| 39 | + |
| 40 | +## Top-Level nvm Commands and Internal Functions |
| 41 | + |
| 42 | +### Core Commands |
| 43 | + |
| 44 | +#### `nvm install [version]` |
| 45 | +- **Internal functions**: `nvm_install_binary()`, `nvm_install_source()`, `nvm_download_artifact()` |
| 46 | +- Downloads and installs specified Node.js version |
| 47 | +- Supports LTS versions, version ranges, and aliases |
| 48 | +- Can install from binary or compile from source |
| 49 | + |
| 50 | +#### `nvm use [version]` |
| 51 | +- **Internal functions**: `nvm_resolve_alias()`, `nvm_version_path()`, `nvm_change_path()` |
| 52 | +- Switches current shell to use specified Node.js version |
| 53 | +- Updates PATH environment variable |
| 54 | +- Supports `.nvmrc` file integration |
| 55 | + |
| 56 | +#### `nvm ls [pattern]` |
| 57 | +- **Internal functions**: `nvm_ls()`, `nvm_tree_contains_path()` |
| 58 | +- Lists installed Node.js versions |
| 59 | +- Supports pattern matching and filtering |
| 60 | +- Shows current version and aliases |
| 61 | + |
| 62 | +#### `nvm ls-remote [pattern]` |
| 63 | +- **Internal functions**: `nvm_ls_remote()`, `nvm_download()`, `nvm_ls_remote_index_tab()` |
| 64 | +- Lists available Node.js versions from nodejs.org |
| 65 | +- Supports LTS filtering and pattern matching |
| 66 | +- Downloads version index on-demand |
| 67 | + |
| 68 | +#### `nvm alias [name] [version]` |
| 69 | +- **Internal functions**: `nvm_alias()`, `nvm_alias_path()` |
| 70 | +- Creates symbolic links for version aliases |
| 71 | +- Special aliases: `default`, `node`, `stable`, `unstable` |
| 72 | +- Stored in `$NVM_DIR/alias/` directory |
| 73 | + |
| 74 | +#### `nvm current` |
| 75 | +- **Internal functions**: `nvm_ls_current()` |
| 76 | +- Shows currently active Node.js version |
| 77 | +- Returns "system" if using system Node.js |
| 78 | + |
| 79 | +#### `nvm which [version]` |
| 80 | +- **Internal functions**: `nvm_version_path()`, `nvm_resolve_alias()` |
| 81 | +- Shows path to specified Node.js version |
| 82 | +- Resolves aliases and version strings |
| 83 | + |
| 84 | +### Utility Commands |
| 85 | + |
| 86 | +#### `nvm cache clear|dir` |
| 87 | +- Cache management for downloaded binaries |
| 88 | +- Clears or shows cache directory path |
| 89 | + |
| 90 | +#### `nvm debug` |
| 91 | +- Diagnostic information for troubleshooting |
| 92 | +- Shows environment, tool versions, and paths |
| 93 | + |
| 94 | +#### `nvm deactivate` |
| 95 | +- Removes nvm modifications from current shell |
| 96 | +- Restores original PATH |
| 97 | + |
| 98 | +#### `nvm unload` |
| 99 | +- Completely removes nvm from shell environment |
| 100 | +- Unsets all nvm functions and variables |
| 101 | + |
| 102 | +### Internal Function Categories |
| 103 | + |
| 104 | +#### Version Resolution |
| 105 | +- `nvm_resolve_alias()` - Resolves aliases to version numbers |
| 106 | +- `nvm_version()` - Finds best matching local version |
| 107 | +- `nvm_remote_version()` - Finds best matching remote version |
| 108 | +- `nvm_normalize_version()` - Standardizes version strings |
| 109 | + |
| 110 | +#### Installation Helpers |
| 111 | +- `nvm_install_binary()` - Downloads and installs precompiled binaries |
| 112 | +- `nvm_install_source()` - Compiles Node.js from source |
| 113 | +- `nvm_download_artifact()` - Downloads tarballs or binaries |
| 114 | +- `nvm_compute_checksum()` - Verifies download integrity |
| 115 | + |
| 116 | +#### Path Management |
| 117 | +- `nvm_change_path()` - Updates PATH for version switching |
| 118 | +- `nvm_strip_path()` - Removes nvm paths from PATH |
| 119 | +- `nvm_version_path()` - Gets installation path for version |
| 120 | + |
| 121 | +#### Utility Functions |
| 122 | +- `nvm_echo()`, `nvm_err()` - Output functions |
| 123 | +- `nvm_has()` - Checks if command exists |
| 124 | +- `nvm_is_zsh()` - Shell detection |
| 125 | +- `nvm_sanitize_path()` - Cleans sensitive data from paths |
| 126 | + |
| 127 | +## Running Tests |
| 128 | + |
| 129 | +### Test Framework |
| 130 | +nvm uses the **urchin** test framework for shell script testing. |
| 131 | + |
| 132 | +### Test Structure |
| 133 | +``` |
| 134 | +test/ |
| 135 | +├── fast/ # Quick unit tests |
| 136 | +├── slow/ # Integration tests |
| 137 | +├── sourcing/ # Shell sourcing tests |
| 138 | +├── install_script/ # Installation script tests |
| 139 | +├── installation_node/ # Node installation tests |
| 140 | +└── common.sh # Shared test utilities |
| 141 | +``` |
| 142 | + |
| 143 | +### Running Tests |
| 144 | + |
| 145 | +#### Install Dependencies |
| 146 | +```bash |
| 147 | +npm install # Installs urchin, semver, and replace tools |
| 148 | +``` |
| 149 | + |
| 150 | +#### Run All Tests |
| 151 | +```bash |
| 152 | +npm test # Runs tests in current shell |
| 153 | +make test # Runs tests in all supported shells |
| 154 | +make test-bash # Runs tests only in bash |
| 155 | +make test-zsh # Runs tests only in zsh |
| 156 | +``` |
| 157 | + |
| 158 | +#### Run Specific Test Suites |
| 159 | +```bash |
| 160 | +make TEST_SUITE=fast test # Only fast tests |
| 161 | +make TEST_SUITE=slow test # Only slow tests |
| 162 | +make SHELLS=bash test # Only bash shell |
| 163 | +``` |
| 164 | + |
| 165 | +#### Individual Test Execution |
| 166 | +```bash |
| 167 | +./test/fast/Unit\ tests/nvm_get_arch # Run single test |
| 168 | +urchin test/fast/ # Run fast test suite |
| 169 | +``` |
| 170 | + |
| 171 | +### Test Writing Guidelines |
| 172 | +- Tests should work across all supported shells (sh, bash, dash, zsh) |
| 173 | +- Use `die()` function for test failures |
| 174 | +- Clean up after tests in cleanup functions |
| 175 | +- Mock external dependencies when needed |
| 176 | +- Place mocks in `test/mocks/` directory |
| 177 | + |
| 178 | +## Shell Environment Setup |
| 179 | + |
| 180 | +### Supported Shells |
| 181 | +- **bash** - Full feature support |
| 182 | +- **zsh** - Full feature support |
| 183 | +- **dash** - Basic POSIX support |
| 184 | +- **sh** - Basic POSIX support |
| 185 | +- **ksh** - Limited support (experimental) |
| 186 | + |
| 187 | +### Installing Shell Environments |
| 188 | + |
| 189 | +#### Ubuntu/Debian |
| 190 | +```bash |
| 191 | +sudo apt-get update |
| 192 | +sudo apt-get install bash zsh dash ksh |
| 193 | +``` |
| 194 | + |
| 195 | +#### macOS |
| 196 | +```bash |
| 197 | +# zsh is default, install others via Homebrew |
| 198 | +brew install bash dash ksh |
| 199 | +``` |
| 200 | + |
| 201 | +#### Manual Shell Testing |
| 202 | +```bash |
| 203 | +# Test in specific shell |
| 204 | +bash -c "source nvm.sh && nvm --version" |
| 205 | +zsh -c "source nvm.sh && nvm --version" |
| 206 | +dash -c ". nvm.sh && nvm --version" |
| 207 | +``` |
| 208 | + |
| 209 | +### Shell-Specific Considerations |
| 210 | +- **zsh**: Requires `setopt local_options shwordsplit` for word splitting |
| 211 | +- **dash**: Limited feature set, avoid bash-specific syntax |
| 212 | +- **ksh**: Some features may not work, primarily for compatibility testing |
| 213 | + |
| 214 | +## CI Environment Details |
| 215 | + |
| 216 | +### GitHub Actions Workflows |
| 217 | + |
| 218 | +#### `.github/workflows/tests.yml` |
| 219 | +- Runs test suite across multiple shells and test suites |
| 220 | +- Uses `script` command for proper TTY simulation |
| 221 | +- Matrix strategy covers shell × test suite combinations |
| 222 | +- Excludes install_script tests from non-bash shells |
| 223 | + |
| 224 | +#### `.github/workflows/shellcheck.yml` |
| 225 | +- Lints all shell scripts using shellcheck |
| 226 | +- Tests against multiple shell targets (bash, sh, dash, ksh) |
| 227 | +- Uses Homebrew to install latest shellcheck version |
| 228 | + |
| 229 | +#### `.github/workflows/lint.yml` |
| 230 | +- Runs additional linting and formatting checks |
| 231 | +- Validates documentation and code style |
| 232 | + |
| 233 | +### Travis CI (Legacy) |
| 234 | +- Configured in `.travis.yml` |
| 235 | +- Tests on multiple Ubuntu versions |
| 236 | +- Installs shell environments via apt packages |
| 237 | + |
| 238 | +### CI Test Execution |
| 239 | +```bash |
| 240 | +# Simulate CI environment locally |
| 241 | +export TRAVIS_BUILD_DIR="" # Disable Travis-specific logic |
| 242 | +export GITHUB_ACTIONS="" # Disable GitHub Actions logic |
| 243 | +make test |
| 244 | +``` |
| 245 | + |
| 246 | +## Setting Up shellcheck Locally |
| 247 | + |
| 248 | +### Installation |
| 249 | + |
| 250 | +#### macOS (Homebrew) |
| 251 | +```bash |
| 252 | +brew install shellcheck |
| 253 | +``` |
| 254 | + |
| 255 | +#### Ubuntu/Debian |
| 256 | +```bash |
| 257 | +sudo apt-get install shellcheck |
| 258 | +``` |
| 259 | + |
| 260 | +#### From Source |
| 261 | +```bash |
| 262 | +# Download from https://github.com/koalaman/shellcheck/releases |
| 263 | +wget https://github.com/koalaman/shellcheck/releases/download/latest/shellcheck-latest.linux.x86_64.tar.xz |
| 264 | +tar -xf shellcheck-latest.linux.x86_64.tar.xz |
| 265 | +sudo cp shellcheck-latest/shellcheck /usr/local/bin/ |
| 266 | +``` |
| 267 | + |
| 268 | +### Usage |
| 269 | + |
| 270 | +#### Lint Main Files |
| 271 | +```bash |
| 272 | +shellcheck -s bash nvm.sh |
| 273 | +shellcheck -s bash install.sh |
| 274 | +shellcheck -s bash nvm-exec |
| 275 | +shellcheck -s bash bash_completion |
| 276 | +``` |
| 277 | + |
| 278 | +#### Lint Across Shell Types |
| 279 | +```bash |
| 280 | +shellcheck -s sh nvm.sh # POSIX sh |
| 281 | +shellcheck -s bash nvm.sh # Bash extensions |
| 282 | +shellcheck -s dash nvm.sh # Dash compatibility |
| 283 | +shellcheck -s ksh nvm.sh # Ksh compatibility |
| 284 | +``` |
| 285 | + |
| 286 | +#### Common shellcheck Directives in nvm |
| 287 | +- `# shellcheck disable=SC2039` - Allow bash extensions in POSIX mode |
| 288 | +- `# shellcheck disable=SC2016` - Allow literal `$` in single quotes |
| 289 | +- `# shellcheck disable=SC2001` - Allow sed usage instead of parameter expansion |
| 290 | +- `# shellcheck disable=SC3043` - Allow `local` keyword (bash extension) |
| 291 | + |
| 292 | +### Fixing shellcheck Issues |
| 293 | +1. **Quoting**: Always quote variables: `"${VAR}"` instead of `$VAR` |
| 294 | +2. **POSIX compliance**: Avoid bash-specific features in portable sections |
| 295 | +3. **Array usage**: Use `set --` for positional parameters instead of arrays |
| 296 | +4. **Local variables**: Mark as bash-specific or avoid in POSIX functions |
| 297 | + |
| 298 | +## Development Best Practices |
| 299 | + |
| 300 | +### Code Style |
| 301 | +- Use 2-space indentation |
| 302 | +- Follow POSIX shell guidelines for portability |
| 303 | +- Prefix internal functions with `nvm_` |
| 304 | +- Use `nvm_echo` instead of `echo` for output |
| 305 | +- Use `nvm_err` for error messages |
| 306 | + |
| 307 | +### Compatibility |
| 308 | +- Test changes across all supported shells |
| 309 | +- Avoid bash-specific features in core functionality |
| 310 | +- Use `nvm_is_zsh` checks when zsh-specific behavior needed |
| 311 | +- Mock external dependencies in tests |
| 312 | + |
| 313 | +### Performance |
| 314 | +- Cache expensive operations (like remote version lists) |
| 315 | +- Use local variables to avoid scope pollution |
| 316 | +- Minimize subprocess calls where possible |
| 317 | +- Implement lazy loading for optional features |
| 318 | + |
| 319 | +### Debugging |
| 320 | +- Use `nvm debug` command for environment information |
| 321 | +- Enable verbose output with `set -x` during development |
| 322 | +- Test with `NVM_DEBUG=1` environment variable |
| 323 | +- Check `$NVM_DIR/.cache` for cached data issues |
| 324 | + |
| 325 | +## Common Gotchas |
| 326 | + |
| 327 | +1. **PATH modification**: nvm modifies PATH extensively; be careful with restoration |
| 328 | +2. **Shell sourcing**: nvm must be sourced, not executed as a script |
| 329 | +3. **Version resolution**: Aliases, partial versions, and special keywords interact complexly |
| 330 | +4. **Platform differences**: Handle differences between Linux, macOS, and other Unix systems |
| 331 | +5. **Network dependencies**: Many operations require internet access for version lists |
| 332 | +6. **Concurrent access**: Multiple shells can conflict when installing versions simultaneously |
| 333 | + |
| 334 | +This guide should help GitHub Copilot understand the nvm codebase structure, testing procedures, and development environment setup requirements. |
0 commit comments