feat: refactor plugin architecture, enhance linting, CI & tooling

- Major refactor of core Fish functions for modularity, caching, and error handling
- Improved `.editorconfig` and Makefile for stricter formatting and linting standards
- Expanded linting support: added EditorConfig checks, auto-install for missing tools, and Makefile targets
- Enhanced CI workflow with clearer permissions and job steps in GitHub Actions
- Updated documentation in `README.md` and `CLAUDE.md` to reflect new features, advanced developer tools, and contribution guidelines
- Improved Node.js version manager detection, switching, and installation logic
- Added/updated utility functions for configuration, silent mode, notifications, and version extraction
- Various bug fixes, code quality improvements, and expanded test coverage
This commit is contained in:
2025-07-16 15:12:14 +03:00
parent 8c9febaf8f
commit 5b680f06ac
30 changed files with 3106 additions and 248 deletions

View File

@@ -1,14 +0,0 @@
{
"permissions": {
"allow": [
"Bash(fish_indent:*)",
"Bash(find:*)",
"Bash(make lint-fish:*)",
"Bash(make lint-json:*)",
"Bash(make lint-markdown:*)",
"Bash(make lint-fix:*)",
"Bash(make lint:*)"
],
"deny": []
}
}

View File

@@ -9,3 +9,20 @@ trim_trailing_whitespace = true
[*.fish]
indent_size = 4
indent_style = space
[Makefile]
indent_style = tab
max_line_length = 80
[*.sh]
max_line_length = 120
indent_size = 2
indent_style = space
[*.yml]
indent_size = 2
indent_style = space
[*.json]
indent_size = 2
indent_style = space

50
.github/install_editorconfig-checker.sh vendored Executable file
View File

@@ -0,0 +1,50 @@
#!/bin/bash
set -e
echo "Downloading editorconfig-checker..."
BASE_URL="https://github.com/editorconfig-checker/editorconfig-checker/releases/latest/download"
# Detect OS and architecture
OS="$(uname -s)"
ARCH="$(uname -m)"
case "$OS" in
Darwin)
[ "$ARCH" = "arm64" ] && ARCH="arm64" || ARCH="amd64"
URL="$BASE_URL/ec-darwin-${ARCH}.tar.gz"
;;
Linux)
[ "$ARCH" = "aarch64" ] && ARCH="arm64" || ARCH="amd64"
URL="$BASE_URL/ec-linux-${ARCH}.tar.gz"
;;
*)
echo "Unsupported OS: $OS"
exit 1
;;
esac
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
curl -L "$URL" | tar -xz -C "$TMPDIR"
# Choose install directory
INSTALL_DIR="${XDG_BIN_HOME:-$HOME/bin}"
[ -d "$INSTALL_DIR" ] || INSTALL_DIR="/usr/local/bin"
echo "Installing to $INSTALL_DIR..."
mkdir -p "$INSTALL_DIR" 2>/dev/null || true
if mv "$TMPDIR/bin/ec" "$INSTALL_DIR/editorconfig-checker" 2>/dev/null; then
echo "✓ Installed editorconfig-checker to $INSTALL_DIR"
elif sudo mv "$TMPDIR/bin/ec" "$INSTALL_DIR/editorconfig-checker" 2>/dev/null; then
echo "✓ Installed editorconfig-checker to $INSTALL_DIR (with sudo)"
else
echo "Could not install to $INSTALL_DIR, using local copy"
mkdir -p bin
mv "$TMPDIR/bin/ec" bin/editorconfig-checker
echo "Add $(pwd)/bin to your PATH to use editorconfig-checker"
fi
echo "Installation complete!"

View File

@@ -8,11 +8,12 @@ on:
pull_request:
branches: [master, main]
permissions:
contents: read
packages: read
statuses: write
jobs:
SuperLinter:
uses: ivuorinen/actions/pr-lint@625c37446b1c7e219755a40807f825c9283f6e05 # 25.7.7
Linter:
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
statuses: write
steps:
- uses: ivuorinen/actions/pr-lint@625c37446b1c7e219755a40807f825c9283f6e05 # 25.7.7

1
.gitignore vendored
View File

@@ -22,3 +22,4 @@
*~
Session.vim
Sessionx.vim
.claude/settings.local.json

View File

@@ -4,4 +4,4 @@
"MD013": { "line_length": 120 },
"MD033": false,
"MD041": false
}
}

116
CLAUDE.md
View File

@@ -19,22 +19,34 @@ The plugin consists of two main Fish functions:
### Linting and Code Quality
The project uses a comprehensive linting setup with automatic tool installation:
```bash
# Install all linting tools (markdownlint-cli, jsonlint, jq)
# Install all linting tools (markdownlint-cli, jsonlint, jq, editorconfig-checker)
make install-tools
# Run all linting checks
# Run all linting checks (Fish, Markdown, JSON, EditorConfig)
make lint
# Fix auto-fixable linting issues
make lint-fix
# Individual linting commands
make lint-fish # Lint Fish shell files
make lint-markdown # Lint Markdown files
make lint-json # Lint JSON files
make lint-fish # Lint Fish shell files (formatting + syntax)
make lint-markdown # Lint Markdown files (style, headers, lists)
make lint-json # Lint JSON files (syntax validation)
make lint-editorconfig # Check EditorConfig compliance (line endings, indentation)
```
#### Supported Linting Tools
- **Fish shell**: `fish_indent` for formatting, `fish -n` for syntax validation
- **Markdown**: `markdownlint-cli` with custom configuration (`.markdownlint.json`)
- **JSON**: `jsonlint` or `jq` for syntax validation
- **EditorConfig**: `editorconfig-checker` (auto-installed if missing)
The linting system automatically downloads missing tools and follows XDG standards for installation.
#### Manual Fish Commands
```fish
@@ -48,14 +60,19 @@ find . -name "*.fish" -exec fish_indent --check {} \;
fish -n functions/*.fish completions/*.fish
```
### Installation/Testing
### Testing
```bash
# Test plugin installation using Makefile
make test
# Run all tests (unit + integration)
tests/test_runner.fish
# Test plugin installation in CI environment
make test-ci
# Run specific test types
make test-unit # Unit tests only
make test-integration # Integration tests only
# Test plugin installation
make test # Local installation test
make test-ci # CI environment test
```
#### Manual Installation Commands
@@ -86,6 +103,38 @@ nvm_auto_use_config debounce 1000
nvm_auto_use_config exclude "build"
```
### Developer Tools
```fish
# Security and validation
nvm_security check_version "18.17.0" # Validate version format and policies
nvm_security audit # Comprehensive security audit
nvm_security policy set min_version "16.0.0" # Set security policies
# Smart recommendations
nvm_recommendations suggest_version new_project # Get version recommendations
nvm_recommendations upgrade_path # Plan upgrade strategy
nvm_recommendations security_update # Security-focused updates
# Diagnostics and debugging
nvm_doctor check # Comprehensive health check
nvm_doctor system # System information
nvm_doctor managers # Check version managers
nvm_doctor fix all # Auto-fix common issues
# Cache management
nvm_cache stats # Cache statistics
nvm_cache clear # Clear all cache
nvm_cache get "key" # Get cached value
# Async operations
nvm_async version_check "file" # Non-blocking version check
nvm_async cleanup # Clean up background jobs
# Error recovery
nvm_error_recovery manager_failure "nvm" "18.0.0" # Handle manager failures
```
### Testing the Functions
```fish
@@ -105,18 +154,59 @@ nvm_version_status
## Key Implementation Details
### Core Architecture
- The plugin hooks into Fish's variable change system using `--on-variable PWD`
- Supports multiple Node.js version managers: nvm, fnm, volta, asdf
- Supports multiple file formats: `.nvmrc`, `.node-version`, `.tool-versions`, `package.json` engines.node
- Includes performance optimizations: caching, debouncing, directory exclusions
- Configurable features: silent mode, auto-install toggle, notifications, project-only mode
- Error handling includes checking if Node.js is available and graceful fallback when versions can't be switched
- The search for version files traverses up the directory tree until it finds one or reaches the root directory
### Performance Features
- **XDG-compliant caching** with configurable TTL for version lookups and manager availability
- **Async operations** for non-blocking version checks using Fish background jobs
- **Debouncing** to prevent rapid version switching during directory navigation
- **Smart directory exclusions** to skip unnecessary processing
### Security & Reliability
- **Version validation** with format checking and policy enforcement
- **Security vulnerability scanning** with CVE checking (online and offline)
- **Error recovery mechanisms** with graceful degradation and fallback strategies
- **Input sanitization** to prevent injection attacks through version files
### Advanced Capabilities
- **Smart recommendations** for version selection, upgrades, and security updates
- **Comprehensive diagnostics** with the `nvm_doctor` command for troubleshooting
- **Extensive testing suite** with unit and integration tests
- **Configuration management** with persistent settings and policy enforcement
## Code Quality Standards
### Fish Shell Code
- All Fish code must be formatted with `fish_indent` before committing
- Functions should include description flags (`-d "description"`)
- Use proper Fish conventions for variable scoping (`set -l`, `set -g`, `set -gx`)
- Include comprehensive error handling and input validation
- Follow Fish best practices for command substitution and string handling
### General Standards
- **Makefile**: 80-character line limit, tab indentation
- **Markdown**: 120-character line limit, consistent heading structure
- **JSON**: Valid syntax, proper formatting
- **EditorConfig**: Consistent line endings (LF), final newlines, no trailing whitespace
### CI/CD Integration
- GitHub Actions automatically runs all linting checks on push/PR
- All linting must pass before merging
- Use `make test-ci` for testing plugin installation in CI environments
### Tool Installation
- Missing linting tools are automatically installed during `make install-tools`
- Installation respects XDG standards: `$XDG_BIN_HOME``$HOME/bin``/usr/local/bin`
- Uses secure temporary directories (`mktemp`) for downloads

View File

@@ -1,6 +1,12 @@
# Makefile for nvm-auto-use.fish
.PHONY: help install-tools lint lint-fish lint-markdown lint-json lint-fix lint-check test clean
# URLs and constants
FISHER_BASE := https://raw.githubusercontent.com/jorgebucaran/fisher/main
FISHER_URL := $(FISHER_BASE)/functions/fisher.fish
.PHONY: help install-tools lint lint-fish lint-markdown lint-json \
lint-fix lint-check lint-editorconfig test test-ci test-unit \
test-integration clean
# Default target
help:
@@ -12,28 +18,28 @@ help:
@echo " lint-json - Lint JSON files"
@echo " lint-fix - Fix auto-fixable linting issues"
@echo " lint-check - Check linting without fixing"
@echo " lint-editorconfig - Check EditorConfig compliance"
@echo " test - Run tests (install plugin locally)"
@echo " test-ci - Run tests in CI environment"
@echo " test-unit - Run unit tests only"
@echo " test-integration - Run integration tests only"
@echo " clean - Clean temporary files"
# Install all required linting tools
install-tools:
@echo "Installing linting tools..."
# Install markdownlint-cli for markdown linting
@if ! command -v markdownlint >/dev/null 2>&1; then \
echo "Installing markdownlint-cli..."; \
npm install -g markdownlint-cli; \
else \
echo "markdownlint-cli already installed"; \
fi
# Install jsonlint for JSON linting
@if ! command -v jsonlint >/dev/null 2>&1; then \
echo "Installing jsonlint..."; \
npm install -g jsonlint; \
else \
echo "jsonlint already installed"; \
fi
# Install jq for JSON processing (backup)
@if ! command -v jq >/dev/null 2>&1; then \
echo "Installing jq..."; \
if command -v brew >/dev/null 2>&1; then \
@@ -51,18 +57,19 @@ install-tools:
@echo "All linting tools installed!"
# Run all linting checks
lint: lint-fish lint-markdown lint-json
lint: lint-fish lint-markdown lint-json lint-editorconfig
# Lint Fish shell files
lint-fish:
@echo "Linting Fish files..."
@find . -name "*.fish" -type f | while read -r file; do \
echo "Checking $$file..."; \
fish_indent --check "$$file" || { \
echo "Formatting issues found in $$file"; \
exit 1; \
}; \
done
@find . \
-name "*.fish" \
-type f \
-exec sh -c \
'echo "Checking $$1..."; \
fish_indent --check "$$1" || { \
echo "Formatting issues found in $$1"; exit 1; }' \
sh {} \;
@echo "Validating Fish syntax..."
@fish -n functions/*.fish completions/*.fish 2>/dev/null || { \
echo "Syntax errors found in Fish files"; \
@@ -86,24 +93,36 @@ lint-markdown:
# Lint JSON files
lint-json:
@echo "Linting JSON files..."
@find . -name "*.json" -type f | while read -r file; do \
echo "Checking $$file..."; \
@find . \
-name "*.json" \
-type f \
-exec sh -c \
'file="$$1"; echo "Checking $$file..."; \
if command -v jsonlint >/dev/null 2>&1; then \
jsonlint "$$file" >/dev/null || { \
echo "JSON syntax error in $$file"; \
exit 1; \
}; \
echo "JSON syntax error in $$file"; exit 1; }; \
elif command -v jq >/dev/null 2>&1; then \
jq empty "$$file" >/dev/null || { \
echo "JSON syntax error in $$file"; \
exit 1; \
}; \
echo "JSON syntax error in $$file"; exit 1; }; \
else \
echo "No JSON linter found, skipping $$file"; \
fi; \
done
echo "No JSON linter found, skipping $$file"; fi' \
sh {} \;
@echo "JSON files passed linting!"
# Check EditorConfig compliance
lint-editorconfig:
@echo "Checking EditorConfig compliance..."
@if command -v editorconfig-checker >/dev/null 2>&1; then \
editorconfig-checker; \
elif command -v ec >/dev/null 2>&1; then \
ec; \
else \
echo "Installing editorconfig-checker..."; \
.github/install_editorconfig-checker.sh; \
editorconfig-checker; \
fi
@echo "EditorConfig compliance passed!"
# Fix auto-fixable linting issues
lint-fix:
@echo "Fixing linting issues..."
@@ -134,7 +153,7 @@ test:
test-ci:
@echo "Testing plugin installation in CI..."
@fish -c "\
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source; \
curl -sL $(FISHER_URL) | source; \
fisher install jorgebucaran/fisher; \
if fisher list | string match -q '*ivuorinen/nvm-auto-use.fish*'; \
echo 'Plugin already installed, skipping installation'; \
@@ -143,9 +162,30 @@ test-ci:
end; \
echo 'Plugin test completed successfully in CI!'"
# Run unit tests
test-unit:
@echo "Running unit tests..."
@chmod +x tests/test_runner.fish
@for test in tests/unit/*.fish; do \
echo "Running $$test..."; \
fish "$$test" || exit 1; \
done
@echo "Unit tests completed!"
# Run integration tests
test-integration:
@echo "Running integration tests..."
@chmod +x tests/test_runner.fish
@for test in tests/integration/*.fish; do \
echo "Running $$test..."; \
fish "$$test" || exit 1; \
done
@echo "Integration tests completed!"
# Clean temporary files
clean:
@echo "Cleaning temporary files..."
@find . -name "*.tmp" -type f -delete 2>/dev/null || true
@find . -name ".DS_Store" -type f -delete 2>/dev/null || true
@echo "Cleanup complete!"
@nvm_cache clear 2>/dev/null || true
@echo "Cleanup complete!"

View File

@@ -42,12 +42,16 @@ fisher install ivuorinen/nvm-auto-use.fish
- Manager preference selection
- Project-only activation mode
### 🔔 **Developer Tools**
### 🔔 **Advanced Developer Tools**
- **Security features**: Version validation, CVE checking, policy enforcement
- **Smart recommendations**: Intelligent version suggestions and upgrade paths
- **Comprehensive diagnostics**: `nvm_doctor` for troubleshooting and health checks
- **Performance optimization**: XDG-compliant caching with TTL, async operations
- **Error recovery**: Graceful degradation and fallback mechanisms
- Desktop notifications for version switches
- Environment variable export (`NODE_VERSION`)
- Fish shell completions
- Detailed status reporting
- Fish shell completions and detailed status reporting
## Quick Start
@@ -100,6 +104,47 @@ nvm_auto_use_config reset
| `.tool-versions` | Tool + version | `nodejs 18.17.0` |
| `package.json` | engines.node field | `"engines": {"node": ">=16.0.0"}` |
## Advanced Features
### Security & Validation
```fish
# Security audit and validation
nvm_security audit # Comprehensive security check
nvm_security check_version "18.17.0" # Validate version format
nvm_security policy set min_version "16.0.0" # Set minimum version policy
```
### Smart Recommendations
```fish
# Get intelligent recommendations
nvm_recommendations suggest_version new_project # Project-specific suggestions
nvm_recommendations upgrade_path # Plan safe upgrades
nvm_recommendations security_update # Security-focused updates
```
### Diagnostics & Troubleshooting
```fish
# Comprehensive system diagnostics
nvm_doctor check # Full health check
nvm_doctor managers # Check version manager status
nvm_doctor security # Security audit
nvm_doctor fix all # Auto-fix common issues
```
### Performance & Caching
```fish
# Cache management (XDG-compliant)
nvm_cache stats # View cache statistics
nvm_cache clear # Clear all cached data
# Async operations for better performance
nvm_async version_check "file" # Non-blocking version checks
```
## Utility Functions
```fish
@@ -125,6 +170,45 @@ nvm_compat_detect
- [volta](https://volta.sh/)
- [asdf](https://asdf-vm.com/) with nodejs plugin
## Development
### Contributing
This project uses comprehensive linting and code quality tools:
```bash
# Install development tools
make install-tools
# Run all linting checks
make lint
# Fix auto-fixable issues
make lint-fix
# Test plugin installation
make test
```
### Code Quality
- **Fish shell**: Automatic formatting with `fish_indent`
- **Markdown**: Style checking with `markdownlint`
- **JSON**: Syntax validation with `jsonlint`/`jq`
- **EditorConfig**: Compliance checking with `editorconfig-checker`
All tools are automatically installed if missing, following XDG directory standards.
### GitHub Actions
The project includes CI/CD workflows that automatically:
- Run all linting checks on push/PR
- Test plugin installation in clean environments
- Ensure code quality standards are maintained
See [CLAUDE.md](CLAUDE.md) for detailed development guidelines.
## Uninstall
```fish

106
functions/nvm_async.fish Normal file
View File

@@ -0,0 +1,106 @@
function nvm_async -d "Async operations for non-blocking version management"
set -l operation $argv[1]
switch $operation
case version_check
_nvm_async_version_check $argv[2]
case manager_check
_nvm_async_manager_check $argv[2]
case cleanup
_nvm_async_cleanup
case wait
_nvm_async_wait $argv[2] $argv[3]
case '*'
echo "Usage: nvm_async [version_check|manager_check|cleanup|wait] [args...]"
return 1
end
end
function _nvm_async_version_check -d "Async version check operation"
set -l version_file $argv[1]
set -l cache_key (_nvm_cache_key "$version_file")
# Try cache first
if set -l cached_result (nvm_cache get "$cache_key" 60)
echo "$cached_result"
return 0
end
# Background job for version extraction
fish -c "
set result (nvm_extract_version '$version_file' 2>/dev/null)
if test -n \"\$result\"
nvm_cache set '$cache_key' \"\$result\"
echo \"\$result\"
end
" &
# Return job ID for potential cleanup
jobs -l | tail -n 1 | grep -o '[0-9]*'
end
function _nvm_async_manager_check -d "Async manager availability check"
set -l manager $argv[1]
set -l cache_key (_nvm_cache_manager_key "$manager")
# Try cache first (longer TTL for manager availability)
if set -l cached_result (nvm_cache get "$cache_key" 3600)
echo "$cached_result"
return 0
end
# Background check
fish -c "
if command -q '$manager'
nvm_cache set '$cache_key' 'available'
echo 'available'
else
nvm_cache set '$cache_key' 'unavailable'
echo 'unavailable'
end
" &
jobs -l | tail -n 1 | grep -o '[0-9]*'
end
function _nvm_async_cleanup -d "Clean up completed background jobs"
for job in (jobs -p)
if not kill -0 $job 2>/dev/null
jobs -p | grep -v $job
end
end
end
function _nvm_async_wait -d "Wait for async job with timeout"
set -l job_id $argv[1]
set -l timeout $argv[2]
if test -z "$timeout"
set timeout 2
end
# Wait for job with timeout
set -l count 0
while test $count -lt (math "$timeout * 10")
if not jobs -p | grep -q "^$job_id\$"
return 0
end
sleep 0.1
set count (math "$count + 1")
end
# Timeout reached, kill job
kill -9 $job_id 2>/dev/null
return 1
end
function _nvm_async_safe_read -d "Safely read async operation result"
set -l cache_key $argv[1]
set -l fallback $argv[2]
set -l result (nvm_cache get "$cache_key")
if test -n "$result"
echo "$result"
else if test -n "$fallback"
echo "$fallback"
end
end

View File

@@ -1,130 +1,155 @@
function nvm_auto_use --on-variable PWD
# Detect available Node.js version manager
set -l available_managers (nvm_compat_detect 2>/dev/null | tail -n 1)
if test -z "$available_managers"
# Select the Node.js version manager
set -l manager (_nvm_auto_use_select_manager)
if test -z "$manager"
return
end
# Use preferred manager or first available
set -l manager
if test -n "$_nvm_auto_use_preferred_manager"
if contains "$_nvm_auto_use_preferred_manager" $available_managers
set manager "$_nvm_auto_use_preferred_manager"
end
# Debounce rapid directory changes
if _nvm_auto_use_should_debounce
return
end
if test -z "$manager"
set manager $available_managers[1]
# Check for excluded directories
if _nvm_auto_use_is_excluded_dir
return
end
# Check if project detection is enabled and we're in a Node.js project
# Project-only mode: only activate in Node.js projects
if set -q _nvm_auto_use_project_only
if not nvm_project_detect
return
end
end
# Export NODE_VERSION environment variable
# Export NODE_VERSION environment variable if available
if command -q node
set -gx NODE_VERSION (node -v 2>/dev/null | string replace 'v' '')
end
# Check for excluded directories
set -l current_dir (pwd)
for pattern in $_nvm_auto_use_excluded_dirs node_modules .git
if string match -q "*/$pattern" "$current_dir"; or string match -q "*/$pattern/*" "$current_dir"
return
end
end
# Debouncing: prevent rapid switching
set -l debounce_ms (_nvm_auto_use_get_debounce)
set -l current_time (date +%s%3N 2>/dev/null; or date +%s)
if test -n "$_nvm_auto_use_last_change"
set -l time_diff (math "$current_time - $_nvm_auto_use_last_change")
if test $time_diff -lt $debounce_ms
return
end
end
set -g _nvm_auto_use_last_change $current_time
# Find version file and its mtime
set -l nvmrc_file (nvm_find_nvmrc)
set -l nvmrc_mtime (_nvm_auto_use_get_mtime "$nvmrc_file")
# Cache check: if same file and version, skip processing
if test "$nvmrc_file" = "$_nvm_auto_use_cached_file"
# Skip if cache is valid
if _nvm_auto_use_is_cache_valid "$nvmrc_file" "$nvmrc_mtime"
return
end
if test -n "$nvmrc_file"
set -l node_version (nvm_extract_version "$nvmrc_file")
# Cache the file path
set -g _nvm_auto_use_cached_file "$nvmrc_file"
# Validate node version format (basic semver or major version)
if not string match -qr '^v?[0-9]+(\..*)?$' "$node_version"
if not set -q _nvm_auto_use_silent
echo "Invalid Node.js version format in $nvmrc_file: $node_version" >&2
end
return 1
end
# Remove 'v' prefix if present
set node_version (string replace -r '^v' '' "$node_version")
# Cache the version
set -g _nvm_auto_use_cached_version "$node_version"
# Check the current version
set -l current_version
if command -q node
set current_version (node -v 2>/dev/null | sed 's/v//')
end
if test "$node_version" != "$current_version"
if not set -q _nvm_auto_use_silent
echo "Switching to Node.js v$node_version"
end
# Send notification if enabled
if not set -q _nvm_auto_use_silent
nvm_notify "Switched to Node.js v$node_version"
end
if not nvm_compat_use $manager $node_version 2>/dev/null
# Check if auto-install is disabled
if set -q _nvm_auto_use_no_install
if not set -q _nvm_auto_use_silent
echo "Node.js version $node_version not found (auto-install disabled)" >&2
end
return 1
end
if not set -q _nvm_auto_use_silent
echo "Node.js version $node_version not found, installing..."
end
if nvm_compat_install $manager $node_version >/dev/null 2>&1
nvm_compat_use $manager $node_version >/dev/null 2>&1
if not set -q _nvm_auto_use_silent
echo "Installed and switched to Node.js v$node_version"
end
else
if not set -q _nvm_auto_use_silent
echo "Failed to install Node.js version $node_version" >&2
end
return 1
end
end
# Update cached version after successful switch
set -g _nvm_auto_use_cached_version "$node_version"
# Update NODE_VERSION environment variable
set -gx NODE_VERSION "$node_version"
end
_nvm_auto_use_switch_version "$manager" "$nvmrc_file" "$nvmrc_mtime"
else
# Clear cache if no .nvmrc found
set -e _nvm_auto_use_cached_file
set -e _nvm_auto_use_cached_version
_nvm_auto_use_clear_cache
end
end
function _nvm_auto_use_select_manager
set -l available_managers (nvm_compat_detect 2>/dev/null)
if test -z "$available_managers"
return
end
if test -n "$_nvm_auto_use_preferred_manager"
if contains "$_nvm_auto_use_preferred_manager" $available_managers
echo "$_nvm_auto_use_preferred_manager"
return
end
end
echo $available_managers[1]
end
function _nvm_auto_use_should_debounce
set -l debounce_ms (_nvm_auto_use_get_debounce)
set -l current_time (date +%s%3N 2>/dev/null; or math "(date +%s) * 1000")
if test -n "$_nvm_auto_use_last_change"
set -l time_diff (math "$current_time - $_nvm_auto_use_last_change")
if test $time_diff -lt $debounce_ms
return 0
end
end
set -g _nvm_auto_use_last_change $current_time
return 1
end
function _nvm_auto_use_is_excluded_dir
set -l current_dir (pwd)
set -l patterns $_nvm_auto_use_excluded_dirs node_modules .git
for pattern in $patterns
if string match -q "*/$pattern" "$current_dir"; or string match -q "*/$pattern/*" "$current_dir"
return 0
end
end
return 1
end
function _nvm_auto_use_get_mtime
set -l file $argv[1]
if test -n "$file"
stat -c %Y "$file" 2>/dev/null; or stat -f %m "$file" 2>/dev/null
end
end
function _nvm_auto_use_is_cache_valid
set -l file $argv[1]
set -l mtime $argv[2]
if test "$file" = "$_nvm_auto_use_cached_file"; and test "$mtime" = "$_nvm_auto_use_cached_mtime"
return 0
end
return 1
end
function _nvm_auto_use_switch_version
set -l manager $argv[1]
set -l nvmrc_file $argv[2]
set -l nvmrc_mtime $argv[3]
set -l node_version (nvm_extract_version "$nvmrc_file")
set -g _nvm_auto_use_cached_file "$nvmrc_file"
set -g _nvm_auto_use_cached_mtime "$nvmrc_mtime"
if not string match -qr '^v?[0-9]+(\..*)?$' "$node_version"
if not set -q _nvm_auto_use_silent
echo "Invalid Node.js version format in $nvmrc_file: $node_version" >&2
end
return 1
end
set node_version (string replace -r '^v' '' "$node_version")
set -g _nvm_auto_use_cached_version "$node_version"
set -l current_version
if command -q node
set current_version (node -v 2>/dev/null | sed 's/v//')
end
if test "$node_version" != "$current_version"
if not set -q _nvm_auto_use_silent
echo "Switching to Node.js v$node_version"
nvm_notify "Switched to Node.js v$node_version"
end
if not nvm_compat_use $manager $node_version 2>/dev/null
if set -q _nvm_auto_use_no_install
if not set -q _nvm_auto_use_silent
echo "Node.js version $node_version not found (auto-install disabled)" >&2
end
return 1
end
if not set -q _nvm_auto_use_silent
echo "Node.js version $node_version not found, installing..."
end
if nvm_compat_install $manager $node_version >/dev/null 2>&1
nvm_compat_use $manager $node_version >/dev/null 2>&1
if not set -q _nvm_auto_use_silent
echo "Installed and switched to Node.js v$node_version"
end
else
if not set -q _nvm_auto_use_silent
echo "Failed to install Node.js version $node_version" >&2
end
return 1
end
end
set -g _nvm_auto_use_cached_version "$node_version"
set -gx NODE_VERSION "$node_version"
end
end
function _nvm_auto_use_clear_cache
set -e _nvm_auto_use_cached_file
set -e _nvm_auto_use_cached_version
set -e _nvm_auto_use_cached_mtime
end

View File

@@ -1,88 +1,126 @@
function nvm_auto_use_config -d "Configure nvm-auto-use settings"
if test (count $argv) -eq 0
echo "nvm-auto-use configuration:"
echo " auto_install: "(test -n "$_nvm_auto_use_no_install"; and echo "disabled"; or echo "enabled")
echo " silent: "(test -n "$_nvm_auto_use_silent"; and echo "enabled"; or echo "disabled")
echo " debounce_ms: "(_nvm_auto_use_get_debounce)
echo " excluded_dirs: "(_nvm_auto_use_get_excluded_dirs)
echo " preferred_manager: "(test -n "$_nvm_auto_use_preferred_manager"; and echo "$_nvm_auto_use_preferred_manager"; or echo "auto-detect")
_nvm_auto_use_config_show
return
end
switch $argv[1]
case auto_install
switch $argv[2]
case on enable true 1
set -e _nvm_auto_use_no_install
echo "Auto-install enabled"
case off disable false 0
set -g _nvm_auto_use_no_install 1
echo "Auto-install disabled"
case '*'
echo "Usage: nvm_auto_use_config auto_install [on|off]"
end
_nvm_auto_use_config_auto_install $argv[2]
case silent
switch $argv[2]
case on enable true 1
set -g _nvm_auto_use_silent 1
echo "Silent mode enabled"
case off disable false 0
set -e _nvm_auto_use_silent
echo "Silent mode disabled"
case '*'
echo "Usage: nvm_auto_use_config silent [on|off]"
end
_nvm_auto_use_config_silent $argv[2]
case debounce
if test -n "$argv[2]" -a (string match -r '^[0-9]+$' "$argv[2]")
set -g _nvm_auto_use_debounce_ms $argv[2]
echo "Debounce set to $argv[2]ms"
else
echo "Usage: nvm_auto_use_config debounce <milliseconds>"
end
_nvm_auto_use_config_debounce $argv[2]
case exclude
if test -n "$argv[2]"
set -g _nvm_auto_use_excluded_dirs $_nvm_auto_use_excluded_dirs $argv[2]
echo "Added $argv[2] to excluded directories"
else
echo "Usage: nvm_auto_use_config exclude <directory_pattern>"
end
_nvm_auto_use_config_exclude $argv[2]
case include
if test -n "$argv[2]"
set -l index (contains -i "$argv[2]" $_nvm_auto_use_excluded_dirs)
if test -n "$index"
set -e _nvm_auto_use_excluded_dirs[$index]
echo "Removed $argv[2] from excluded directories"
else
echo "$argv[2] was not in excluded directories"
end
else
echo "Usage: nvm_auto_use_config include <directory_pattern>"
end
_nvm_auto_use_config_include $argv[2]
case manager
if test -n "$argv[2]"
if contains "$argv[2]" nvm fnm volta asdf
set -g _nvm_auto_use_preferred_manager "$argv[2]"
echo "Preferred manager set to $argv[2]"
else
echo "Unsupported manager. Supported: nvm, fnm, volta, asdf"
end
else
set -e _nvm_auto_use_preferred_manager
echo "Reset to auto-detect manager"
end
_nvm_auto_use_config_manager $argv[2]
case reset
set -e _nvm_auto_use_no_install
set -e _nvm_auto_use_silent
set -e _nvm_auto_use_debounce_ms
set -e _nvm_auto_use_excluded_dirs
set -e _nvm_auto_use_preferred_manager
echo "Configuration reset to defaults"
_nvm_auto_use_config_reset
case '*'
echo "Usage: nvm_auto_use_config [auto_install|silent|debounce|exclude|include|manager|reset] [value]"
return 1
end
end
function _nvm_auto_use_config_show
echo "nvm-auto-use configuration:"
echo " auto_install: "(test -n "$_nvm_auto_use_no_install"; and echo "disabled"; or echo "enabled")
echo " silent: "(test -n "$_nvm_auto_use_silent"; and echo "enabled"; or echo "disabled")
echo " debounce_ms: "(_nvm_auto_use_get_debounce)
echo " excluded_dirs: "(_nvm_auto_use_get_excluded_dirs)
echo " preferred_manager: "(test -n "$_nvm_auto_use_preferred_manager"; and echo "$_nvm_auto_use_preferred_manager"; or echo "auto-detect")
end
function _nvm_auto_use_config_auto_install
set -l value $argv[1]
switch $value
case on enable true 1
set -e _nvm_auto_use_no_install
echo "Auto-install enabled"
case off disable false 0
set -g _nvm_auto_use_no_install 1
echo "Auto-install disabled"
case '*'
echo "Usage: nvm_auto_use_config auto_install [on|off]"
end
end
function _nvm_auto_use_config_silent
set -l value $argv[1]
switch $value
case on enable true 1
set -g _nvm_auto_use_silent 1
echo "Silent mode enabled"
case off disable false 0
set -e _nvm_auto_use_silent
echo "Silent mode disabled"
case '*'
echo "Usage: nvm_auto_use_config silent [on|off]"
end
end
function _nvm_auto_use_config_debounce
set -l value $argv[1]
if test -n "$value" -a (string match -r '^[0-9]+$' "$value")
set -g _nvm_auto_use_debounce_ms $value
echo "Debounce set to $value ms"
else
echo "Usage: nvm_auto_use_config debounce <milliseconds>"
end
end
function _nvm_auto_use_config_exclude
set -l value $argv[1]
if test -n "$value"
set -g _nvm_auto_use_excluded_dirs $_nvm_auto_use_excluded_dirs $value
echo "Added $value to excluded directories"
else
echo "Usage: nvm_auto_use_config exclude <directory_pattern>"
end
end
function _nvm_auto_use_config_include
set -l value $argv[1]
if test -n "$value"
set -l index (contains -i "$value" $_nvm_auto_use_excluded_dirs)
if test -n "$index"
set -e _nvm_auto_use_excluded_dirs[$index]
echo "Removed $value from excluded directories"
else
echo "$value was not in excluded directories"
end
else
echo "Usage: nvm_auto_use_config include <directory_pattern>"
end
end
function _nvm_auto_use_config_manager
set -l value $argv[1]
if test -n "$value"
if contains "$value" nvm fnm volta asdf
set -g _nvm_auto_use_preferred_manager "$value"
echo "Preferred manager set to $value"
else
echo "Unsupported manager. Supported: nvm, fnm, volta, asdf"
end
else
set -e _nvm_auto_use_preferred_manager
echo "Reset to auto-detect manager"
end
end
function _nvm_auto_use_config_reset
set -e _nvm_auto_use_no_install
set -e _nvm_auto_use_silent
set -e _nvm_auto_use_debounce_ms
set -e _nvm_auto_use_excluded_dirs
set -e _nvm_auto_use_preferred_manager
echo "Configuration reset to defaults"
end
function _nvm_auto_use_get_debounce
if test -n "$_nvm_auto_use_debounce_ms"
echo "$_nvm_auto_use_debounce_ms"

View File

@@ -13,7 +13,7 @@ function nvm_auto_use_silent -d "Enable or disable silent mode for nvm-auto-use"
set -g _nvm_auto_use_silent 1
echo "Silent mode enabled"
case off disable false 0
set -e _nvm_auto_use_silent
set -e -g _nvm_auto_use_silent
echo "Silent mode disabled"
case '*'
echo "Usage: nvm_auto_use_silent [on|off]"

110
functions/nvm_cache.fish Normal file
View File

@@ -0,0 +1,110 @@
function nvm_cache -d "XDG-compliant cache management with TTL"
set -l action $argv[1]
set -l key $argv[2]
set -l value $argv[3]
set -l ttl $argv[4]
switch $action
case get
_nvm_cache_get "$key" "$ttl"
case set
_nvm_cache_set "$key" "$value"
case delete
_nvm_cache_delete "$key"
case clear
_nvm_cache_clear
case stats
_nvm_cache_stats
case '*'
echo "Usage: nvm_cache [get|set|delete|clear|stats] <key> [value] [ttl]"
return 1
end
end
function _nvm_cache_dir -d "Get XDG cache directory for nvm-auto-use"
if set -q XDG_CACHE_HOME
echo "$XDG_CACHE_HOME/nvm-auto-use"
else
echo "$HOME/.cache/nvm-auto-use"
end
end
function _nvm_cache_get -d "Get cache value by key, respecting TTL"
set -l key $argv[1]
set -l ttl $argv[2]
set -l cache_dir (_nvm_cache_dir)
set -l cache_file "$cache_dir/$key"
if not test -f "$cache_file"
return 1
end
# Check TTL
set -l cache_time (stat -c %Y "$cache_file" 2>/dev/null; or stat -f %m "$cache_file" 2>/dev/null)
set -l current_time (date +%s)
set -l default_ttl 300 # 5 minutes default
if test -n "$ttl"
set default_ttl $ttl
end
if test (math "$current_time - $cache_time") -gt $default_ttl
rm "$cache_file" 2>/dev/null
return 1
end
cat "$cache_file"
return 0
end
function _nvm_cache_set -d "Set cache value by key"
set -l key $argv[1]
set -l value $argv[2]
set -l cache_dir (_nvm_cache_dir)
set -l cache_file "$cache_dir/$key"
if test -z "$value"
return 1
end
mkdir -p "$cache_dir" 2>/dev/null
echo "$value" >"$cache_file" 2>/dev/null
return $status
end
function _nvm_cache_delete -d "Delete cache value by key"
set -l key $argv[1]
set -l cache_dir (_nvm_cache_dir)
set -l cache_file "$cache_dir/$key"
rm "$cache_file" 2>/dev/null
return 0
end
function _nvm_cache_clear -d "Clear all cache files"
set -l cache_dir (_nvm_cache_dir)
rm -rf "$cache_dir" 2>/dev/null
return 0
end
function _nvm_cache_stats -d "Show cache statistics"
set -l cache_dir (_nvm_cache_dir)
if test -d "$cache_dir"
echo "Cache directory: $cache_dir"
echo "Cache files: "(find "$cache_dir" -type f 2>/dev/null | wc -l)
echo "Cache size: "(du -sh "$cache_dir" 2>/dev/null | cut -f1)
else
echo "No cache directory found"
end
return 0
end
function _nvm_cache_key -d "Generate cache key from directory and file"
set -l dir (pwd)
set -l file_hash (echo "$argv[1]" | shasum | cut -d' ' -f1)
echo "dir_$(echo "$dir" | shasum | cut -d' ' -f1)_$file_hash"
end
function _nvm_cache_manager_key -d "Generate cache key for manager availability"
set -l manager $argv[1]
echo "manager_$manager"
end

View File

@@ -36,13 +36,13 @@ function nvm_compat_use -a manager version -d "Use specified version with detect
switch $manager
case nvm
nvm use $version
nvm use $version; or return $status
case fnm
fnm use $version
fnm use $version; or return $status
case volta
volta pin node@$version
volta pin node@$version; or return $status
case asdf
asdf local nodejs $version
asdf local nodejs $version; or return $status
case '*'
echo "Unsupported manager: $manager"
return 1
@@ -57,13 +57,13 @@ function nvm_compat_install -a manager version -d "Install specified version wit
switch $manager
case nvm
nvm install $version
nvm install $version; or return $status
case fnm
fnm install $version
fnm install $version; or return $status
case volta
volta install node@$version
volta install node@$version; or return $status
case asdf
asdf install nodejs $version
asdf install nodejs $version; or return $status
case '*'
echo "Unsupported manager: $manager"
return 1

428
functions/nvm_doctor.fish Normal file
View File

@@ -0,0 +1,428 @@
function nvm_doctor -d "Comprehensive diagnostic and debugging tool"
set -l action $argv[1]
switch $action
case check
_nvm_doctor_full_check
case system
_nvm_doctor_system_info
case managers
_nvm_doctor_check_managers
case permissions
_nvm_doctor_check_permissions
case config
_nvm_doctor_check_config
case cache
_nvm_doctor_check_cache
case security
_nvm_doctor_security_audit
case performance
_nvm_doctor_performance_check
case fix
_nvm_doctor_auto_fix $argv[2..-1]
case '*'
echo "Usage: nvm_doctor [check|system|managers|permissions|config|cache|security|performance|fix] [args...]"
echo
echo "Commands:"
echo " check - Run comprehensive diagnostic check"
echo " system - Show system information"
echo " managers - Check version manager status"
echo " permissions - Check file and directory permissions"
echo " config - Validate configuration"
echo " cache - Check cache status and health"
echo " security - Run security audit"
echo " performance - Analyze performance issues"
echo " fix - Attempt to fix common issues"
return 1
end
end
function _nvm_doctor_full_check -d "Run comprehensive diagnostic check"
echo "🩺 NVM Auto-Use Doctor - Comprehensive Check"
echo "============================================="
echo
set -l issues 0
# System check
echo "🖥️ System Information"
echo ---------------------
_nvm_doctor_system_info
echo
# Manager check
echo "🔧 Version Manager Status"
echo -------------------------
_nvm_doctor_check_managers
set issues (math "$issues + $status")
echo
# Configuration check
echo "⚙️ Configuration Status"
echo ------------------------
_nvm_doctor_check_config
set issues (math "$issues + $status")
echo
# Permissions check
echo "🔐 Permissions Check"
echo -------------------
_nvm_doctor_check_permissions
set issues (math "$issues + $status")
echo
# Cache check
echo "🗄️ Cache Status"
echo ----------------
_nvm_doctor_check_cache
set issues (math "$issues + $status")
echo
# Security audit
echo "🔒 Security Audit"
echo -----------------
_nvm_doctor_security_audit
set issues (math "$issues + $status")
echo
# Performance check
echo "⚡ Performance Analysis"
echo ----------------------
_nvm_doctor_performance_check
set issues (math "$issues + $status")
echo
# Summary
echo "📋 Diagnostic Summary"
echo "====================="
if test $issues -eq 0
echo "✅ All checks passed! Your nvm-auto-use setup is healthy."
else
echo "⚠️ Found $issues issue(s) that may need attention."
echo "💡 Run 'nvm_doctor fix' to attempt automatic fixes."
end
return $issues
end
function _nvm_doctor_system_info -d "Display system information"
echo "OS: "(uname -s)" "(uname -r)
echo "Architecture: "(uname -m)
echo "Shell: $SHELL"
echo "Fish version: "(fish --version)
if command -q node
echo "Node.js: "(node --version)
else
echo "Node.js: Not installed"
end
if command -q npm
echo "npm: "(npm --version)
else
echo "npm: Not available"
end
echo "PATH entries: "(echo $PATH | string split ':' | wc -l)
echo "Current directory: "(pwd)
end
function _nvm_doctor_check_managers -d "Check version manager availability and status"
set -l issues 0
set -l managers (nvm_compat_detect 2>/dev/null)
if test -z "$managers"
echo "❌ No Node.js version managers found"
echo " Install at least one: nvm, fnm, volta, or asdf"
set issues (math "$issues + 1")
else
echo "✅ Found managers: $managers"
# Check each manager's status
for manager in (echo $managers | string split ' ')
echo " 📋 $manager status:"
switch $manager
case nvm
if test -f "$HOME/.nvm/nvm.sh"
echo " ✅ NVM script found"
if command -q nvm
echo " ✅ NVM command available"
else
echo " ⚠️ NVM not in PATH (normal for Fish)"
end
else
echo " ❌ NVM installation not found"
set issues (math "$issues + 1")
end
case fnm
if command -q fnm
echo " ✅ FNM available: "(fnm --version)
else
echo " ❌ FNM not found in PATH"
set issues (math "$issues + 1")
end
case volta
if command -q volta
echo " ✅ Volta available: "(volta --version)
else
echo " ❌ Volta not found in PATH"
set issues (math "$issues + 1")
end
case asdf
if command -q asdf
echo " ✅ asdf available: "(asdf --version)
if asdf plugin list | grep -q nodejs
echo " ✅ nodejs plugin installed"
else
echo " ❌ nodejs plugin not installed"
set issues (math "$issues + 1")
end
else
echo " ❌ asdf not found in PATH"
set issues (math "$issues + 1")
end
end
end
end
return $issues
end
function _nvm_doctor_check_permissions -d "Check file and directory permissions"
set -l issues 0
# Check Fish functions directory
set -l functions_dir (dirname (status current-filename))
if test -d "$functions_dir"
echo "✅ Functions directory accessible: $functions_dir"
# Check individual function files
for func_file in "$functions_dir"/nvm_*.fish
if test -r "$func_file"
echo "$(basename $func_file) readable"
else
echo "$(basename $func_file) not readable"
set issues (math "$issues + 1")
end
end
else
echo "❌ Functions directory not found"
set issues (math "$issues + 1")
end
# Check cache directory permissions
set -l cache_dir
if set -q XDG_CACHE_HOME
set cache_dir "$XDG_CACHE_HOME/nvm-auto-use"
else
set cache_dir "$HOME/.cache/nvm-auto-use"
end
if test -d "$cache_dir"
if test -w "$cache_dir"
echo "✅ Cache directory writable: $cache_dir"
else
echo "❌ Cache directory not writable: $cache_dir"
set issues (math "$issues + 1")
end
else
echo " Cache directory doesn't exist (will be created as needed)"
end
# Check current directory permissions for version files
if test -r "."
echo "✅ Current directory readable"
for version_file in .nvmrc .node-version .tool-versions package.json
if test -f "$version_file"
if test -r "$version_file"
echo "$version_file readable"
else
echo "$version_file not readable"
set issues (math "$issues + 1")
end
end
end
else
echo "❌ Current directory not readable"
set issues (math "$issues + 1")
end
return $issues
end
function _nvm_doctor_check_config -d "Validate configuration"
set -l issues 0
echo "Configuration variables:"
# Check debounce setting
set -l debounce (_nvm_auto_use_get_debounce 2>/dev/null)
if test -n "$debounce"
echo " ✅ Debounce: ${debounce}ms"
else
echo " Debounce: Default (500ms)"
end
# Check excluded directories
set -l excluded (_nvm_auto_use_get_excluded_dirs 2>/dev/null)
echo " ✅ Excluded dirs: $excluded"
# Check auto-install setting
if set -q _nvm_auto_use_no_install
echo " ✅ Auto-install: Disabled"
else
echo " ✅ Auto-install: Enabled"
end
# Check silent mode
if set -q _nvm_auto_use_silent
echo " ✅ Silent mode: Enabled"
else
echo " ✅ Silent mode: Disabled"
end
# Check preferred manager
if set -q _nvm_auto_use_preferred_manager
echo " ✅ Preferred manager: $_nvm_auto_use_preferred_manager"
else
echo " ✅ Preferred manager: Auto-detect"
end
# Validate security policies
echo "Security policies:"
nvm_security policy list 2>/dev/null || echo " No security policies set"
return $issues
end
function _nvm_doctor_check_cache -d "Check cache status and health"
set -l issues 0
# Get cache stats
nvm_cache stats
# Check for corrupted cache files
set -l cache_dir
if set -q XDG_CACHE_HOME
set cache_dir "$XDG_CACHE_HOME/nvm-auto-use"
else
set cache_dir "$HOME/.cache/nvm-auto-use"
end
if test -d "$cache_dir"
set -l cache_files (find "$cache_dir" -type f 2>/dev/null)
for cache_file in $cache_files
if test -s "$cache_file"
echo "$(basename $cache_file) valid"
else
echo " ⚠️ $(basename $cache_file) empty (may be normal)"
end
end
# Check for very old cache files
set -l old_files (find "$cache_dir" -type f -mtime +7 2>/dev/null)
if test -n "$old_files"
echo " Found "(echo "$old_files" | wc -l)" cache files older than 7 days"
end
else
echo " No cache directory found"
end
return $issues
end
function _nvm_doctor_security_audit -d "Run security audit"
nvm_security audit
end
function _nvm_doctor_performance_check -d "Analyze performance issues"
set -l issues 0
echo "Performance analysis:"
# Check for excessive cache files
set -l cache_dir
if set -q XDG_CACHE_HOME
set cache_dir "$XDG_CACHE_HOME/nvm-auto-use"
else
set cache_dir "$HOME/.cache/nvm-auto-use"
end
if test -d "$cache_dir"
set -l cache_count (find "$cache_dir" -type f 2>/dev/null | wc -l)
if test $cache_count -gt 100
echo " ⚠️ Large number of cache files ($cache_count) - consider cleanup"
set issues (math "$issues + 1")
else
echo " ✅ Reasonable cache size ($cache_count files)"
end
end
# Check for very long directory paths
set -l current_path (pwd)
set -l path_length (string length "$current_path")
if test $path_length -gt 200
echo " ⚠️ Very long current path may slow operations: $path_length characters"
set issues (math "$issues + 1")
else
echo " ✅ Path length reasonable: $path_length characters"
end
# Check for deep directory nesting
set -l depth (echo "$current_path" | string replace -a '/' '\n' | wc -l)
if test $depth -gt 15
echo " ⚠️ Deep directory nesting may slow file searches: $depth levels"
set issues (math "$issues + 1")
else
echo " ✅ Directory depth reasonable: $depth levels"
end
return $issues
end
function _nvm_doctor_auto_fix -d "Attempt to fix common issues"
set -l fix_type $argv[1]
echo "🔧 Attempting automatic fixes..."
switch $fix_type
case cache
echo "Cleaning up cache..."
nvm_cache clear
echo "✅ Cache cleared"
case permissions
echo "Fixing cache directory permissions..."
set -l cache_dir
if set -q XDG_CACHE_HOME
set cache_dir "$XDG_CACHE_HOME/nvm-auto-use"
else
set cache_dir "$HOME/.cache/nvm-auto-use"
end
mkdir -p "$cache_dir" 2>/dev/null
chmod 755 "$cache_dir" 2>/dev/null
echo "✅ Cache directory permissions fixed"
case config
echo "Resetting configuration to defaults..."
nvm_auto_use_config reset
echo "✅ Configuration reset"
case all
echo "Running all available fixes..."
_nvm_doctor_auto_fix cache
_nvm_doctor_auto_fix permissions
echo "✅ All fixes completed"
case '*'
echo "Available fix types:"
echo " cache - Clear cache files"
echo " permissions - Fix directory permissions"
echo " config - Reset configuration"
echo " all - Run all fixes"
return 1
end
end

View File

@@ -0,0 +1,168 @@
function nvm_error_recovery -d "Error recovery and graceful degradation"
set -l operation $argv[1]
set -l error_context $argv[2]
switch $operation
case manager_failure
set -l manager $argv[2]
set -l target_version $argv[3]
echo "⚠️ $manager failed to switch to version $target_version" >&2
# Try fallback managers
set -l fallback_managers (nvm_compat_detect | string split ' ')
for fallback in $fallback_managers
if test "$fallback" != "$manager"
echo "🔄 Trying fallback manager: $fallback" >&2
if _nvm_error_recovery_try_manager "$fallback" "$target_version"
echo "✅ Successfully switched using $fallback" >&2
return 0
end
end
end
echo "❌ All managers failed. Staying on current version." >&2
return 1
case version_not_found
set -l manager $argv[2]
set -l requested_version $argv[3]
echo "⚠️ Version $requested_version not found" >&2
# Try to find similar versions
set -l suggestions (_nvm_error_recovery_suggest_versions "$manager" "$requested_version")
if test -n "$suggestions"
echo "💡 Available similar versions: $suggestions" >&2
# Auto-select best match if auto_install is disabled
if set -q _nvm_auto_use_no_install
set -l best_match (echo "$suggestions" | string split ' ' | head -n 1)
echo "🔄 Trying closest match: $best_match" >&2
if _nvm_error_recovery_try_manager "$manager" "$best_match"
return 0
end
end
end
return 1
case network_failure
echo "⚠️ Network failure during version operation" >&2
# Check if we have a cached version list
set -l cache_key "versions_$(echo $argv[2] | shasum | cut -d' ' -f1)"
if set -l cached_versions (nvm_cache get "$cache_key" 86400) # 24 hour TTL
echo "📦 Using cached version information" >&2
echo "$cached_versions"
return 0
end
echo "❌ No cached version information available" >&2
return 1
case permission_denied
set -l operation_type $argv[2]
echo "⚠️ Permission denied for $operation_type" >&2
switch $operation_type
case install
echo "💡 Try running with appropriate permissions or check manager configuration" >&2
case switch
echo "💡 Check if the version is already installed or try with sudo" >&2
end
return 1
case timeout
set -l operation_type $argv[2]
set -l timeout_duration $argv[3]
echo "⏱️ Operation '$operation_type' timed out after $timeout_duration seconds" >&2
echo "💡 Consider checking network connection or increasing timeout" >&2
# Kill any hanging processes
nvm_async cleanup
return 1
case corruption
set -l file_path $argv[2]
echo "⚠️ Corrupted file detected: $file_path" >&2
# Try to recover from backup or regenerate
if test -f "$file_path.backup"
echo "🔄 Restoring from backup" >&2
cp "$file_path.backup" "$file_path"
return 0
end
echo "❌ No backup available, manual intervention required" >&2
return 1
case '*'
echo "Unknown error recovery operation: $operation" >&2
return 1
end
end
function _nvm_error_recovery_try_manager -d "Try using a specific manager"
set -l manager $argv[1]
set -l version $argv[2]
if not command -q "$manager"
return 1
end
switch $manager
case nvm
nvm use "$version" 2>/dev/null
case fnm
fnm use "$version" 2>/dev/null
case volta
volta pin "node@$version" 2>/dev/null
case asdf
asdf local nodejs "$version" 2>/dev/null
case '*'
return 1
end
end
function _nvm_error_recovery_suggest_versions -d "Suggest similar available versions"
set -l manager $argv[1]
set -l requested $argv[2]
# Extract major version for suggestions
set -l major (echo "$requested" | string replace -r '^v?([0-9]+).*' '$1')
# Try to get available versions (with error handling)
set -l available_versions
switch $manager
case nvm
set available_versions (nvm list-remote 2>/dev/null | grep "^v$major\." | head -n 5)
case fnm
set available_versions (fnm list-remote 2>/dev/null | grep "^v$major\." | head -n 5)
case asdf
set available_versions (asdf list-all nodejs 2>/dev/null | grep "^$major\." | head -n 5)
end
echo "$available_versions" | string join ' '
end
function _nvm_error_recovery_log -d "Log error for debugging"
set -l error_type $argv[1]
set -l details $argv[2]
# Log to XDG cache directory
set -l log_dir
if set -q XDG_CACHE_HOME
set log_dir "$XDG_CACHE_HOME/nvm-auto-use"
else
set log_dir "$HOME/.cache/nvm-auto-use"
end
mkdir -p "$log_dir" 2>/dev/null
set -l log_file "$log_dir/error.log"
set -l timestamp (date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] $error_type: $details" >>"$log_file"
end

View File

@@ -35,11 +35,15 @@ function nvm_extract_version -a file_path -d "Extract Node.js version from vario
# Standard .nvmrc or .node-version file
set -l version (cat "$actual_file" | string trim)
if test -n "$version"
# Strip leading 'v'
set version (string replace -r '^v' '' "$version")
# Handle nvm aliases
switch "$version"
case 'lts/*' lts latest stable node
if command -q nvm
set version (nvm version-remote "$version" 2>/dev/null | string replace 'v' '')
else if command -q node
set version (node -v 2>/dev/null | string replace -r '^v' '')
end
end
echo "$version"

View File

@@ -8,13 +8,18 @@ function nvm_notify -a message -d "Send notification for Node.js version changes
return
end
# Try different notification methods
if command -q osascript # macOS
# Try different notification methods until one succeeds
if command -q osascript
osascript -e "display notification \"$message\" with title \"nvm-auto-use\""
else if command -q notify-send # Linux
return
end
if command -q notify-send
notify-send nvm-auto-use "$message"
else if command -q terminal-notifier # macOS alternative
return
end
if command -q terminal-notifier
terminal-notifier -title nvm-auto-use -message "$message"
return
end
end

View File

@@ -0,0 +1,354 @@
function nvm_recommendations -d "Smart recommendations for Node.js versions and configurations"
set -l action $argv[1]
switch $action
case suggest_version
_nvm_recommend_version $argv[2..-1]
case upgrade_path
_nvm_recommend_upgrade $argv[2..-1]
case security_update
_nvm_recommend_security_update
case performance
_nvm_recommend_performance
case compatibility
_nvm_recommend_compatibility $argv[2..-1]
case manager
_nvm_recommend_manager
case config
_nvm_recommend_config
case '*'
echo "Usage: nvm_recommendations [suggest_version|upgrade_path|security_update|performance|compatibility|manager|config] [args...]"
return 1
end
end
function _nvm_recommend_version -d "Recommend appropriate Node.js version"
set -l context $argv[1] # 'new_project', 'existing_project', 'migration'
echo "🔍 Analyzing project for Node.js version recommendation..."
# Check for existing version constraints
set -l constraints (_nvm_analyze_version_constraints)
set -l current_version
if command -q node
set current_version (node --version | string replace 'v' '')
end
# Get available managers and their capabilities
set -l available_managers (nvm_compat_detect | string split ' ')
echo
echo "📋 Recommendation Analysis:"
echo "============================"
# Project type detection
set -l project_type (_nvm_detect_project_type)
echo "Project type: $project_type"
if test -n "$current_version"
echo "Current version: $current_version"
end
if test -n "$constraints"
echo "Detected constraints: $constraints"
end
# Generate recommendations
echo
echo "💡 Recommendations:"
echo "==================="
switch $context
case new_project
_nvm_recommend_for_new_project "$project_type"
case existing_project
_nvm_recommend_for_existing_project "$project_type" "$current_version"
case migration
_nvm_recommend_for_migration "$current_version"
case '*'
_nvm_recommend_general "$project_type" "$current_version"
end
end
function _nvm_recommend_for_new_project -d "Recommendations for new projects"
set -l project_type $argv[1]
switch $project_type
case react
echo "• Node.js 18.17.0+ (LTS) - Recommended for React projects"
echo "• Consider Node.js 20.x for latest features"
echo "• Avoid odd-numbered versions (development releases)"
case vue
echo "• Node.js 16.20.0+ - Minimum for Vue 3"
echo "• Node.js 18.17.0+ (LTS) - Recommended"
case angular
echo "• Node.js 18.13.0+ - Required for Angular 15+"
echo "• Node.js 18.17.0+ (LTS) - Recommended"
case nextjs
echo "• Node.js 18.17.0+ - Required for Next.js 13+"
echo "• Node.js 20.x for best performance"
case typescript
echo "• Node.js 18.17.0+ (LTS) - Excellent TypeScript support"
echo "• Node.js 20.x for latest TypeScript features"
case backend
echo "• Node.js 18.17.0+ (LTS) - Stable for production"
echo "• Consider Node.js 20.x for performance improvements"
case '*'
echo "• Node.js 18.17.0+ (LTS) - Safe choice for most projects"
echo "• Node.js 20.x for latest features and performance"
end
echo
echo "💭 General Guidelines:"
echo "• Use LTS versions for production projects"
echo "• Test with latest version for future compatibility"
echo "• Pin exact versions in CI/CD environments"
end
function _nvm_recommend_for_existing_project -d "Recommendations for existing projects"
set -l project_type $argv[1]
set -l current_version $argv[2]
if test -z "$current_version"
echo "• Install Node.js to get version-specific recommendations"
return
end
# Check if current version is LTS
set -l is_lts (_nvm_check_if_lts "$current_version")
set -l is_outdated (_nvm_check_if_outdated "$current_version")
if test "$is_outdated" = true
echo "⚠️ Current version ($current_version) is outdated"
echo "• Consider upgrading to latest LTS for security updates"
# Suggest upgrade path
set -l upgrade_target (_nvm_suggest_upgrade_target "$current_version")
if test -n "$upgrade_target"
echo "• Recommended upgrade: $upgrade_target"
end
else if test "$is_lts" = false
echo " Current version ($current_version) is not LTS"
echo "• Consider switching to LTS for stability"
else
echo "✅ Current version ($current_version) is good"
echo "• No immediate action needed"
end
# Dependency compatibility check
if test -f "package.json"
echo
echo "📦 Dependency Analysis:"
_nvm_analyze_dependencies
end
end
function _nvm_recommend_upgrade -d "Recommend upgrade path"
set -l current_version $argv[1]
if test -z "$current_version"
if command -q node
set current_version (node --version | string replace 'v' '')
else
echo "❌ No Node.js version specified or installed"
return 1
end
end
echo "🔄 Upgrade Path Analysis for Node.js $current_version"
echo "=================================================="
# Check for security issues
nvm_security check_cve "$current_version"
set -l has_vulnerabilities $status
if test $has_vulnerabilities -ne 0
echo
echo "🚨 SECURITY: Immediate upgrade recommended due to vulnerabilities"
end
# Suggest upgrade targets
set -l major_version (echo "$current_version" | string replace -r '^([0-9]+)\..*' '$1')
set -l next_lts (_nvm_get_next_lts "$major_version")
echo
echo "📈 Upgrade Options:"
echo "• Patch upgrade: Stay within current minor version"
echo "• Minor upgrade: Upgrade to latest in major version $major_version"
if test -n "$next_lts"
echo "• Major upgrade: Node.js $next_lts (LTS)"
end
echo
echo "🧪 Testing Strategy:"
echo "1. Test in development environment first"
echo "2. Run full test suite"
echo "3. Check for breaking changes in release notes"
echo "4. Update CI/CD pipelines"
echo "5. Deploy to staging before production"
end
function _nvm_recommend_security_update -d "Recommend security-focused updates"
echo "🔒 Security Update Recommendations"
echo "=================================="
if command -q node
set -l current_version (node --version | string replace 'v' '')
echo "Current version: $current_version"
# Check for vulnerabilities
nvm_security check_cve "$current_version"
set -l has_vulnerabilities $status
if test $has_vulnerabilities -ne 0
echo
echo "🚨 ACTION REQUIRED: Security vulnerabilities found"
echo "• Upgrade immediately to patch security issues"
# Suggest secure versions
set -l secure_versions (_nvm_get_secure_versions)
if test -n "$secure_versions"
echo "• Recommended secure versions: $secure_versions"
end
else
echo
echo "✅ No known vulnerabilities in current version"
echo "• Keep monitoring for security updates"
end
else
echo "❌ Node.js not installed - cannot assess security status"
end
echo
echo "🛡️ Security Best Practices:"
echo "• Keep Node.js updated to latest patch versions"
echo "• Subscribe to Node.js security announcements"
echo "• Use npm audit for dependency vulnerabilities"
echo "• Pin specific versions in production"
end
function _nvm_recommend_performance -d "Performance optimization recommendations"
echo "⚡ Performance Optimization Recommendations"
echo "=========================================="
if command -q node
set -l current_version (node --version | string replace 'v' '')
set -l major_version (echo "$current_version" | string replace -r '^([0-9]+)\..*' '$1')
echo "Current version: $current_version"
echo
# Version-specific performance notes
switch $major_version
case 16
echo "📈 Upgrade to Node.js 18+ for:"
echo "• Better V8 engine performance"
echo "• Improved startup time"
echo "• Enhanced memory usage"
case 18
echo "📈 Consider Node.js 20+ for:"
echo "• Latest V8 optimizations"
echo "• Improved module loading"
echo "• Better async performance"
case 20 21
echo "✅ You're using a modern Node.js version"
echo "• Good performance characteristics"
echo "• Consider latest patch for micro-optimizations"
case '*'
echo "⚠️ Consider upgrading to Node.js 18+ for better performance"
end
end
echo
echo "🎯 Performance Tips:"
echo "• Use --max-old-space-size for memory-intensive apps"
echo "• Enable --experimental-loader for faster imports"
echo "• Consider --enable-source-maps for better debugging"
echo "• Profile with --cpu-prof and --heap-prof"
end
function _nvm_detect_project_type -d "Detect project type from files"
if test -f "package.json"
set -l deps (cat package.json 2>/dev/null)
if echo "$deps" | grep -q '"react"'
echo react
else if echo "$deps" | grep -q '"vue"'
echo vue
else if echo "$deps" | grep -q '"@angular"'
echo angular
else if echo "$deps" | grep -q '"next"'
echo nextjs
else if echo "$deps" | grep -q '"typescript"'
echo typescript
else if echo "$deps" | grep -q '"express"\|"fastify"\|"koa"'
echo backend
else
echo node
end
else
echo general
end
end
function _nvm_analyze_version_constraints -d "Analyze existing version constraints"
set -l constraints
# Check package.json engines
if test -f "package.json" -a command -q jq
set -l engine_constraint (jq -r '.engines.node // empty' package.json 2>/dev/null)
if test -n "$engine_constraint"
set constraints $constraints "package.json: $engine_constraint"
end
end
# Check .nvmrc
if test -f ".nvmrc"
set -l nvmrc_version (cat .nvmrc | string trim)
set constraints $constraints ".nvmrc: $nvmrc_version"
end
echo "$constraints" | string join '; '
end
function _nvm_check_if_lts -d "Check if version is LTS"
set -l version $argv[1]
set -l major (echo "$version" | string replace -r '^([0-9]+)\..*' '$1')
# LTS versions: 16, 18, 20 (even numbers)
if test (math "$major % 2") -eq 0
echo true
else
echo false
end
end
function _nvm_check_if_outdated -d "Check if version is outdated"
set -l version $argv[1]
set -l major (echo "$version" | string replace -r '^([0-9]+)\..*' '$1')
# Simplified check - versions below 16 are definitely outdated
if test $major -lt 16
echo true
else
echo false
end
end
function _nvm_get_next_lts -d "Get next LTS version"
set -l current_major $argv[1]
set -l next_lts
# Determine next LTS based on current major
switch $current_major
case 14 15 16 17
set next_lts "18.17.0"
case 18 19
set next_lts "20.5.0"
case '*'
set next_lts "20.5.0"
end
echo "$next_lts"
end

278
functions/nvm_security.fish Normal file
View File

@@ -0,0 +1,278 @@
function nvm_security -d "Security validation and vulnerability checking"
set -l action $argv[1]
switch $action
case check_version
set -l version $argv[2]
_nvm_security_validate_version "$version"
case check_cve
set -l version $argv[2]
_nvm_security_check_vulnerabilities "$version"
case validate_source
set -l source $argv[2]
_nvm_security_validate_source "$source"
case audit
_nvm_security_audit_current
case policy
set -l policy_action $argv[2]
_nvm_security_policy "$policy_action" $argv[3..-1]
case '*'
echo "Usage: nvm_security [check_version|check_cve|validate_source|audit|policy] [args...]"
return 1
end
end
function _nvm_security_validate_version -d "Validate version string format and safety"
set -l version $argv[1]
# Remove leading 'v' if present
set version (string replace -r '^v' '' "$version")
# Check for valid semver format
if not string match -qr '^\d+\.\d+\.\d+' "$version"
echo "⚠️ Invalid version format: $version" >&2
return 1
end
# Check for suspicious characters
if string match -qr '[;&|`$(){}[\]<>]' "$version"
echo "🚨 Suspicious characters in version: $version" >&2
return 1
end
# Check against minimum supported version
set -l min_version (nvm_security policy get min_version)
if test -n "$min_version"
if _nvm_security_version_compare "$version" "$min_version" -lt
echo "⚠️ Version $version is below minimum required ($min_version)" >&2
return 1
end
end
# Check against maximum allowed version
set -l max_version (nvm_security policy get max_version)
if test -n "$max_version"
if _nvm_security_version_compare "$version" "$max_version" -gt
echo "⚠️ Version $version is above maximum allowed ($max_version)" >&2
return 1
end
end
return 0
end
function _nvm_security_check_vulnerabilities -d "Check version for known vulnerabilities"
set -l version $argv[1]
# Cache key for CVE data
set -l cache_key "cve_check_$(echo $version | shasum | cut -d' ' -f1)"
# Check cache first (24 hour TTL)
if set -l cached_result (nvm_cache get "$cache_key" 86400)
if test "$cached_result" = vulnerable
echo "🚨 Version $version has known vulnerabilities (cached)" >&2
return 1
else if test "$cached_result" = safe
echo "✅ Version $version appears safe (cached)" >&2
return 0
end
end
# Check against known vulnerable versions (offline first)
set -l vulnerable_versions "
16.0.0
16.1.0
16.2.0
18.0.0
18.1.0
"
if string match -q "*$version*" "$vulnerable_versions"
echo "🚨 Version $version has known vulnerabilities" >&2
nvm_cache set "$cache_key" vulnerable
return 1
end
# Try online CVE check if available
if command -q curl
_nvm_security_online_cve_check "$version" "$cache_key"
else
echo " Cannot perform online CVE check (curl not available)" >&2
nvm_cache set "$cache_key" unknown
return 0
end
end
function _nvm_security_online_cve_check -d "Perform online CVE check"
set -l version $argv[1]
set -l cache_key $argv[2]
# Background job for CVE checking to avoid blocking
fish -c "
set cve_result (curl -s --max-time 5 'https://nodejs.org/en/about/security/' 2>/dev/null)
if test \$status -eq 0
if echo \"\$cve_result\" | grep -qi '$version'
nvm_cache set '$cache_key' 'vulnerable'
echo '🚨 Version $version found in security advisories' >&2
else
nvm_cache set '$cache_key' 'safe'
echo '✅ Version $version appears safe' >&2
end
else
nvm_cache set '$cache_key' 'unknown'
echo ' Unable to verify security status online' >&2
end
" &
return 0
end
function _nvm_security_validate_source -d "Validate version file source"
set -l source_file $argv[1]
if not test -f "$source_file"
echo "⚠️ Source file not found: $source_file" >&2
return 1
end
# Check file permissions
if test -w "$source_file" -a (stat -c %a "$source_file" 2>/dev/null || stat -f %Mp%Lp "$source_file" 2>/dev/null) = 777
echo "⚠️ Insecure permissions on $source_file (world-writable)" >&2
end
# Check for suspicious content
set -l content (cat "$source_file")
if string match -qr '[;&|`$(){}[\]<>]' "$content"
echo "🚨 Suspicious content in $source_file" >&2
return 1
end
return 0
end
function _nvm_security_audit_current -d "Audit current Node.js installation"
echo "🔍 Security audit for current Node.js installation"
echo
# Current version info
if command -q node
set -l current_version (node --version 2>/dev/null | string replace 'v' '')
echo "Current version: $current_version"
# Check current version security
nvm_security check_version "$current_version"
nvm_security check_cve "$current_version"
# Check npm security if available
if command -q npm
echo
echo "📦 NPM audit (if available):"
npm audit --audit-level moderate 2>/dev/null || echo "NPM audit not available or no package.json found"
end
else
echo "❌ Node.js not found in PATH"
end
echo
echo "🔧 Version managers found:"
nvm_compat_detect
echo
echo "📋 Security policies:"
nvm_security policy list
end
function _nvm_security_policy -d "Manage security policies"
set -l action $argv[1]
switch $action
case set
set -l key $argv[2]
set -l value $argv[3]
switch $key
case min_version
set -g _nvm_security_min_version "$value"
echo "Set minimum version to: $value"
case max_version
set -g _nvm_security_max_version "$value"
echo "Set maximum version to: $value"
case allow_prerelease
set -g _nvm_security_allow_prerelease "$value"
echo "Allow prerelease versions: $value"
case '*'
echo "Unknown policy key: $key" >&2
return 1
end
case get
set -l key $argv[2]
switch $key
case min_version
echo "$_nvm_security_min_version"
case max_version
echo "$_nvm_security_max_version"
case allow_prerelease
echo "$_nvm_security_allow_prerelease"
case '*'
echo "Unknown policy key: $key" >&2
return 1
end
case list
echo "Security policies:"
echo " min_version: $_nvm_security_min_version"
echo " max_version: $_nvm_security_max_version"
echo " allow_prerelease: $_nvm_security_allow_prerelease"
case reset
set -e _nvm_security_min_version
set -e _nvm_security_max_version
set -e _nvm_security_allow_prerelease
echo "Security policies reset to defaults"
case '*'
echo "Usage: nvm_security policy [set|get|list|reset] [key] [value]"
return 1
end
end
function _nvm_security_version_compare -d "Compare semantic versions"
set -l version1 $argv[1]
set -l version2 $argv[2]
set -l operator $argv[3]
# Simple semver comparison
set -l v1_parts (string split '.' "$version1")
set -l v2_parts (string split '.' "$version2")
for i in (seq 1 3)
set -l v1_part (echo $v1_parts[$i] | string replace -r '[^0-9].*' '')
set -l v2_part (echo $v2_parts[$i] | string replace -r '[^0-9].*' '')
if test -z "$v1_part"
set v1_part 0
end
if test -z "$v2_part"
set v2_part 0
end
if test $v1_part -lt $v2_part
test "$operator" = -lt
return $status
else if test $v1_part -gt $v2_part
test "$operator" = -gt
return $status
end
end
# Versions are equal
test "$operator" = -eq
return $status
end

View File

@@ -9,10 +9,13 @@ end
function nvm_version_status -d "Show detailed Node.js version status"
if command -q node
set -l version (node -v 2>/dev/null)
set -l npm_version (npm -v 2>/dev/null)
set -l version (node -v 2>/dev/null | string replace -r '^v' '')
set -l npm_version
if command -q npm
set npm_version (npm -v 2>/dev/null)
end
echo "Node.js: $version"
echo "Node.js: v$version"
if test -n "$npm_version"
echo "npm: v$npm_version"
end

View File

@@ -0,0 +1,178 @@
#!/usr/bin/env fish
# Integration tests for version switching functionality
# All tests operate under $TEST_DIR (a temporary directory) for safety
source tests/test_runner.fish
function test_nvmrc_detection
echo "Testing .nvmrc file detection..."
# Create test project with .nvmrc in temp dir
mkdir -p "$TEST_DIR/test_project"
echo "18.17.0" >"$TEST_DIR/test_project/.nvmrc"
cd "$TEST_DIR/test_project"
set -l found_file (nvm_find_nvmrc)
assert_contains "$found_file" ".nvmrc" "Found .nvmrc file in current directory"
# Test parent directory search
mkdir -p subdir
cd subdir
set found_file (nvm_find_nvmrc)
assert_contains "$found_file" ".nvmrc" "Found .nvmrc file in parent directory"
cd "$TEST_DIR"
rm -rf "$TEST_DIR/test_project"
return 0
end
function test_version_extraction
echo "Testing version extraction from different file formats..."
cd "$TEST_DIR"
# Test .nvmrc
echo "18.17.0" >test.nvmrc
set -l version (nvm_extract_version "test.nvmrc")
assert_equals "$version" "18.17.0" "Extracted version from .nvmrc"
# Test .node-version
echo "16.20.0" >test.node-version
set version (nvm_extract_version "test.node-version")
assert_equals "$version" "16.20.0" "Extracted version from .node-version"
# Test .tool-versions
echo "nodejs 20.5.0" >test.tool-versions
set version (nvm_extract_version "test.tool-versions:nodejs")
assert_equals "$version" "20.5.0" "Extracted version from .tool-versions"
# Test package.json (requires jq)
if command -q jq
echo '{"engines": {"node": ">=18.0.0"}}' >test.package.json
set version (nvm_extract_version "test.package.json:engines.node")
assert_equals "$version" "18.0.0" "Extracted version from package.json"
else
echo " Skipping package.json test (jq not available)"
end
# Cleanup
rm -f test.nvmrc test.node-version test.tool-versions test.package.json
return 0
end
function test_manager_detection
echo "Testing version manager detection..."
cd "$TEST_DIR"
set -l managers (nvm_compat_detect)
if test -n "$managers"
echo "✅ Found version managers: $managers"
else
echo " No version managers found (expected in test environment)"
end
return 0
end
function test_error_recovery
echo "Testing error recovery mechanisms..."
cd "$TEST_DIR"
# Test invalid version handling
echo "invalid.version" >invalid.nvmrc
set -l result (nvm_extract_version "invalid.nvmrc" 2>/dev/null)
if test -z "$result"
echo "✅ Invalid version file handled gracefully"
else
echo "❌ Invalid version should return empty result"
end
# Test missing file handling
nvm_extract_version "nonexistent.nvmrc" >/dev/null 2>&1
set -l status_code $status
test $status_code -ne 0
and echo "✅ Missing file handled gracefully"
or echo "❌ Missing file should return error"
rm -f invalid.nvmrc
return 0
end
function test_async_operations
echo "Testing async operations..."
cd "$TEST_DIR"
# Create test version file
echo "18.17.0" >async_test.nvmrc
# Test async version check
set -l job_id (nvm_async version_check "async_test.nvmrc")
if test -n "$job_id"
echo "✅ Async version check started"
# Wait for completion
nvm_async wait "$job_id" 5
and echo "✅ Async operation completed"
or echo "⚠️ Async operation timed out"
else
echo " Async operation may have completed immediately"
end
rm -f async_test.nvmrc
return 0
end
function test_cache_integration
echo "Testing cache integration..."
cd "$TEST_DIR"
# Clear cache first
nvm_cache clear
# Create test file
echo "18.17.0" >cache_test.nvmrc
# First access should miss cache
set -l start_time (date +%s)
set -l version1 (nvm_extract_version "cache_test.nvmrc")
# Second access should hit cache (if caching is implemented)
set -l version2 (nvm_extract_version "cache_test.nvmrc")
assert_equals "$version1" "$version2" "Consistent results from cache"
rm -f cache_test.nvmrc
return 0
end
function main
setup_test_env
set -l failed 0
test_nvmrc_detection; or set failed (math "$failed + 1")
test_version_extraction; or set failed (math "$failed + 1")
test_manager_detection; or set failed (math "$failed + 1")
test_error_recovery; or set failed (math "$failed + 1")
test_async_operations; or set failed (math "$failed + 1")
test_cache_integration; or set failed (math "$failed + 1")
cleanup_test_env
if test $failed -eq 0
echo "🎉 All integration tests passed!"
return 0
else
echo "💥 $failed integration test(s) failed"
return 1
end
end
main

189
tests/test_runner.fish Executable file
View File

@@ -0,0 +1,189 @@
#!/usr/bin/env fish
# Test runner for nvm-auto-use.fish
function run_tests -d "Run all tests"
set -l test_files
set -l failed_tests 0
set -l total_tests 0
echo "🧪 Running nvm-auto-use.fish test suite"
echo "======================================"
# Find all test files
for test_file in tests/unit/*.fish tests/integration/*.fish
if test -f "$test_file"
set test_files $test_files "$test_file"
end
end
if test (count $test_files) -eq 0
echo "❌ No test files found"
return 1
end
# Run each test file
for test_file in $test_files
echo
echo "📁 Running $(basename $test_file)"
echo "$(string repeat -N (string length "📁 Running $(basename $test_file)") -)"
set -l test_result (fish "$test_file")
set -l test_status $status
if test $test_status -eq 0
echo "$(basename $test_file) passed"
else
echo "$(basename $test_file) failed"
set failed_tests (math "$failed_tests + 1")
end
set total_tests (math "$total_tests + 1")
end
# Summary
echo
echo "📊 Test Results"
echo "==============="
echo "Total tests: $total_tests"
echo "Passed: "(math "$total_tests - $failed_tests")
echo "Failed: $failed_tests"
if test $failed_tests -eq 0
echo
echo "🎉 All tests passed!"
return 0
else
echo
echo "💥 $failed_tests test(s) failed"
return 1
end
end
function assert_equals -d "Assert two values are equal"
set -l actual "$argv[1]"
set -l expected "$argv[2]"
set -l message "$argv[3]"
if test "$actual" = "$expected"
echo "$message"
return 0
else
echo "$message"
echo " Expected: '$expected'"
echo " Actual: '$actual'"
return 1
end
end
function assert_not_equals -d "Assert two values are not equal"
set -l actual "$argv[1]"
set -l expected "$argv[2]"
set -l message "$argv[3]"
if test "$actual" != "$expected"
echo "$message"
return 0
else
echo "$message"
echo " Values should not be equal: '$actual'"
return 1
end
end
function assert_contains -d "Assert string contains substring"
set -l string "$argv[1]"
set -l substring "$argv[2]"
set -l message "$argv[3]"
if string match -q "*$substring*" "$string"
echo "$message"
return 0
else
echo "$message"
echo " String: '$string'"
echo " Should contain: '$substring'"
return 1
end
end
function assert_file_exists -d "Assert file exists"
set -l file_path "$argv[1]"
set -l message "$argv[2]"
if test -f "$file_path"
echo "$message"
return 0
else
echo "$message"
echo " File not found: '$file_path'"
return 1
end
end
function assert_command_success -d "Assert command succeeds"
set -l command "$argv[1]"
set -l message "$argv[2]"
if eval "$command" >/dev/null 2>&1
echo "$message"
return 0
else
echo "$message"
echo " Command failed: '$command'"
return 1
end
end
function setup_test_env -d "Set up test environment"
# Create temporary test directory
set -g TEST_DIR (mktemp -d)
cd "$TEST_DIR"
set -g TEST_FIXTURES "$PWD/../tests/fixtures"
# Link or copy test fixtures from tests/fixtures
if test -d "$TEST_FIXTURES"
cp -R "$TEST_FIXTURES" "$TEST_DIR/fixtures"
else
mkdir -p "$TEST_FIXTURES"
echo "18.17.0" >"$TEST_FIXTURES/.nvmrc"
echo "16.20.0" >"$TEST_FIXTURES/.node-version"
echo "nodejs 20.5.0" >"$TEST_FIXTURES/.tool-versions"
echo '{"engines": {"node": ">=18.0.0"}}' >"$TEST_FIXTURES/package.json"
end
echo "🔧 Test environment set up in $TEST_DIR"
end
function cleanup_test_env -d "Clean up test environment"
if set -q TEST_DIR
# Safety checks: never delete /, $HOME, or empty path
if test -z "$TEST_DIR"
echo "⚠️ TEST_DIR is empty, refusing to delete"
return 1
end
if test "$TEST_DIR" = /
echo "⚠️ TEST_DIR is /, refusing to delete"
return 1
end
if test "$TEST_DIR" = "$HOME"
echo "⚠️ TEST_DIR is $HOME, refusing to delete"
return 1
end
if string match -q "$HOME*" "$TEST_DIR"; and test "$TEST_DIR" = "$HOME"
echo "⚠️ TEST_DIR is $HOME or a parent, refusing to delete"
return 1
end
if test (string length "$TEST_DIR") -lt 8
echo "⚠️ TEST_DIR path too short, refusing to delete: $TEST_DIR"
return 1
end
rm -rf "$TEST_DIR"
echo "🧹 Test environment cleaned up"
end
end
# Run tests if this script is executed directly
if test (basename (status current-filename)) = "test_runner.fish"
run_tests
end

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env fish
# Unit tests for nvm_async helper functions
source tests/test_runner.fish
function test_async_version_check
echo "Testing _nvm_async_version_check..."
# Create a test version file
echo "18.17.0" >async_test.nvmrc
# Should return job id (background job)
set -l job_id (_nvm_async_version_check "async_test.nvmrc")
if test -n "$job_id"
echo "✅ _nvm_async_version_check started job $job_id"
else
echo "❌ _nvm_async_version_check did not start a job"
return 1
end
# Wait for job completion
_nvm_async_wait "$job_id" 5
and echo "✅ Async job completed"
or echo "⚠️ Async job timed out"
rm -f async_test.nvmrc
return 0
end
function test_async_manager_check
echo "Testing _nvm_async_manager_check..."
# Should return job id (background job)
set -l job_id (_nvm_async_manager_check "nvm")
if test -n "$job_id"
echo "✅ _nvm_async_manager_check started job $job_id"
else
echo "❌ _nvm_async_manager_check did not start a job"
return 1
end
# Wait for job completion
_nvm_async_wait "$job_id" 5
and echo "✅ Async manager check job completed"
or echo "⚠️ Async manager check job timed out"
return 0
end
function test_async_cleanup
echo "Testing _nvm_async_cleanup..."
# Start a dummy background job
sleep 2 &
set -l job_id (jobs -l | tail -n 1 | grep -o '[0-9]*')
if test -n "$job_id"
echo "✅ Dummy job started: $job_id"
else
echo "❌ Failed to start dummy job"
return 1
end
# Cleanup should not error
_nvm_async_cleanup
echo "✅ _nvm_async_cleanup executed"
return 0
end
function test_async_wait
echo "Testing _nvm_async_wait..."
# Start a quick background job
sleep 1 &
set -l job_id (jobs -l | tail -n 1 | grep -o '[0-9]*')
if test -n "$job_id"
_nvm_async_wait "$job_id" 3
and echo "✅ _nvm_async_wait completed for job $job_id"
or echo "⚠️ _nvm_async_wait timed out for job $job_id"
else
echo "❌ Failed to start background job for wait test"
return 1
end
return 0
end
function main
setup_test_env
set -l failed 0
test_async_version_check; or set failed (math "$failed + 1")
test_async_manager_check; or set failed (math "$failed + 1")
test_async_cleanup; or set failed (math "$failed + 1")
test_async_wait; or set failed (math "$failed + 1")
cleanup_test_env
if test $failed -eq 0
echo "🎉 All async helper tests passed!"
return 0
else
echo "💥 $failed async helper test(s) failed"
return 1
end
end
main

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env fish
# Unit tests for nvm_auto_use_config helper functions
source tests/test_runner.fish
function test_config_show
echo "Testing _nvm_auto_use_config_show..."
# Should print config summary (no error)
_nvm_auto_use_config_show
and echo "✅ Config show prints summary"
or echo "❌ Config show failed"
end
function test_config_auto_install
echo "Testing _nvm_auto_use_config_auto_install..."
_nvm_auto_use_config_auto_install on
test -z "$_nvm_auto_use_no_install"
and echo "✅ Auto-install enabled"
or echo "❌ Auto-install enable failed"
_nvm_auto_use_config_auto_install off
test -n "$_nvm_auto_use_no_install"
and echo "✅ Auto-install disabled"
or echo "❌ Auto-install disable failed"
end
function test_config_silent
echo "Testing _nvm_auto_use_config_silent..."
_nvm_auto_use_config_silent on
test -n "$_nvm_auto_use_silent"
and echo "✅ Silent mode enabled"
or echo "❌ Silent mode enable failed"
_nvm_auto_use_config_silent off
test -z "$_nvm_auto_use_silent"
and echo "✅ Silent mode disabled"
or echo "❌ Silent mode disable failed"
end
function test_config_debounce
echo "Testing _nvm_auto_use_config_debounce..."
_nvm_auto_use_config_debounce 1234
assert_equals "$_nvm_auto_use_debounce_ms" 1234 "Debounce set correctly"
_nvm_auto_use_config_debounce ""
assert_equals "$_nvm_auto_use_debounce_ms" 1234 "Debounce unchanged on invalid input"
end
function test_config_exclude_include
echo "Testing _nvm_auto_use_config_exclude and _nvm_auto_use_config_include..."
set -e _nvm_auto_use_excluded_dirs
_nvm_auto_use_config_exclude testdir
assert_contains "$_nvm_auto_use_excluded_dirs" testdir "Exclude added"
_nvm_auto_use_config_include testdir
assert_not_equals "$_nvm_auto_use_excluded_dirs" testdir "Exclude removed"
end
function test_config_manager
echo "Testing _nvm_auto_use_config_manager..."
_nvm_auto_use_config_manager nvm
assert_equals "$_nvm_auto_use_preferred_manager" nvm "Manager set to nvm"
_nvm_auto_use_config_manager ""
test -z "$_nvm_auto_use_preferred_manager"
and echo "✅ Manager reset to auto-detect"
or echo "❌ Manager reset failed"
_nvm_auto_use_config_manager invalid
assert_not_equals "$_nvm_auto_use_preferred_manager" invalid "Invalid manager not set"
end
function test_config_reset
echo "Testing _nvm_auto_use_config_reset..."
set -g _nvm_auto_use_no_install 1
set -g _nvm_auto_use_silent 1
set -g _nvm_auto_use_debounce_ms 999
set -g _nvm_auto_use_excluded_dirs foo
set -g _nvm_auto_use_preferred_manager nvm
_nvm_auto_use_config_reset
test -z "$_nvm_auto_use_no_install"
and test -z "$_nvm_auto_use_silent"
and test -z "$_nvm_auto_use_debounce_ms"
and test -z "$_nvm_auto_use_excluded_dirs"
and test -z "$_nvm_auto_use_preferred_manager"
and echo "✅ Config reset works"
or echo "❌ Config reset failed"
end
function main
test_config_show
test_config_auto_install
test_config_silent
test_config_debounce
test_config_exclude_include
test_config_manager
test_config_reset
end
main

View File

@@ -0,0 +1,134 @@
#!/usr/bin/env fish
# Unit tests for nvm_auto_use helper functions
source tests/test_runner.fish
function test_select_manager
echo "Testing _nvm_auto_use_select_manager..."
# Mock nvm_compat_detect to return a list
function nvm_compat_detect
echo "nvm fnm volta"
end
set -e _nvm_auto_use_preferred_manager
set -l manager (_nvm_auto_use_select_manager)
assert_equals "$manager" nvm "Default manager selection returns first available"
set -g _nvm_auto_use_preferred_manager volta
set manager (_nvm_auto_use_select_manager)
assert_equals "$manager" volta "Preferred manager selection works"
set -e _nvm_auto_use_preferred_manager
functions -e nvm_compat_detect
end
function test_should_debounce
echo "Testing _nvm_auto_use_should_debounce..."
set -e _nvm_auto_use_last_change
set -g _nvm_auto_use_debounce_ms 1000
# First call should set last_change and return 1 (not debounced)
set result (_nvm_auto_use_should_debounce)
assert_equals "$result" "" "First call not debounced"
# Second call within debounce period should return 0 (debounced)
set result (_nvm_auto_use_should_debounce)
assert_equals "$result" "" "Second call debounced"
set -e _nvm_auto_use_last_change
set -e _nvm_auto_use_debounce_ms
end
function test_is_excluded_dir
echo "Testing _nvm_auto_use_is_excluded_dir..."
set -g _nvm_auto_use_excluded_dirs testdir
set -l orig_pwd (pwd)
cd /
mkdir -p testdir
cd testdir
set result (_nvm_auto_use_is_excluded_dir)
assert_equals "$result" "" "Excluded directory detected"
cd "$orig_pwd"
set -e _nvm_auto_use_excluded_dirs
end
function test_get_mtime
echo "Testing _nvm_auto_use_get_mtime..."
echo test >testfile
set mtime (_nvm_auto_use_get_mtime "testfile")
test -n "$mtime"
and echo "✅ mtime returned: $mtime"
or echo "❌ mtime not returned"
rm -f testfile
end
function test_is_cache_valid
echo "Testing _nvm_auto_use_is_cache_valid..."
set -g _nvm_auto_use_cached_file foo
set -g _nvm_auto_use_cached_mtime 123
set result (_nvm_auto_use_is_cache_valid "foo" "123")
assert_equals "$result" "" "Cache valid returns 0"
set result (_nvm_auto_use_is_cache_valid "bar" "123")
assert_equals "$result" "" "Cache invalid returns 1"
set -e _nvm_auto_use_cached_file
set -e _nvm_auto_use_cached_mtime
end
function test_clear_cache
echo "Testing _nvm_auto_use_clear_cache..."
set -g _nvm_auto_use_cached_file foo
set -g _nvm_auto_use_cached_version bar
set -g _nvm_auto_use_cached_mtime baz
_nvm_auto_use_clear_cache
if not set -q _nvm_auto_use_cached_file
echo "✅ Cached file cleared"
else
echo "❌ Cached file not cleared"
end
if not set -q _nvm_auto_use_cached_version
echo "✅ Cached version cleared"
else
echo "❌ Cached version not cleared"
end
if not set -q _nvm_auto_use_cached_mtime
echo "✅ Cached mtime cleared"
else
echo "❌ Cached mtime not cleared"
end
end
function main
setup_test_env
set -l failed 0
test_select_manager; or set failed (math "$failed + 1")
test_should_debounce; or set failed (math "$failed + 1")
test_is_excluded_dir; or set failed (math "$failed + 1")
test_get_mtime; or set failed (math "$failed + 1")
test_is_cache_valid; or set failed (math "$failed + 1")
test_clear_cache; or set failed (math "$failed + 1")
cleanup_test_env
if test $failed -eq 0
echo "🎉 All nvm_auto_use helper tests passed!"
return 0
else
echo "💥 $failed helper test(s) failed"
return 1
end
end
main

98
tests/unit/test_cache.fish Executable file
View File

@@ -0,0 +1,98 @@
#!/usr/bin/env fish
# Unit tests for nvm_cache.fish
source tests/test_runner.fish
function test_cache_basic_operations
echo "Testing basic cache operations..."
# Test set and get
nvm_cache set test_key test_value
set -l result (nvm_cache get "test_key")
assert_equals "$result" test_value "Cache set and get works"
# Test delete
nvm_cache delete test_key
nvm_cache get test_key
set -l status_code $status
test $status_code -ne 0
and echo "✅ Cache delete works"
or echo "❌ Cache delete failed"
return 0
end
function test_cache_ttl
echo "Testing cache TTL..."
# Set with short TTL
nvm_cache set ttl_key ttl_value
# Should exist immediately
set -l result (nvm_cache get "ttl_key" 10)
assert_equals "$result" ttl_value "Cache value exists within TTL"
# Mock expired cache by setting TTL to 0
set -l result (nvm_cache get "ttl_key" 0)
set -l status_code $status
test $status_code -ne 0
and echo "✅ Cache TTL expiration works"
or echo "❌ Cache TTL expiration failed"
return 0
end
function test_cache_stats
echo "Testing cache stats..."
# Clear cache first
nvm_cache clear
# Add some items
nvm_cache set stats_key1 value1
nvm_cache set stats_key2 value2
# Get stats
set -l stats (nvm_cache stats)
assert_contains "$stats" "Cache files: 2" "Cache stats shows correct file count"
return 0
end
function test_cache_key_generation
echo "Testing cache key generation..."
# Test directory-based key
set -l key1 (_nvm_cache_key "test_file.txt")
set -l key2 (_nvm_cache_key "test_file.txt")
assert_equals "$key1" "$key2" "Same file generates same cache key"
# Test different files generate different keys
set -l key3 (_nvm_cache_key "different_file.txt")
assert_not_equals "$key1" "$key3" "Different files generate different cache keys"
return 0
end
function main
setup_test_env
set -l failed 0
test_cache_basic_operations; or set failed (math "$failed + 1")
test_cache_ttl; or set failed (math "$failed + 1")
test_cache_stats; or set failed (math "$failed + 1")
test_cache_key_generation; or set failed (math "$failed + 1")
cleanup_test_env
if test $failed -eq 0
echo "🎉 All cache tests passed!"
return 0
else
echo "💥 $failed cache test(s) failed"
return 1
end
end
main

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env fish
# Unit tests for nvm_cache helper functions
source tests/test_runner.fish
function test_nvm_cache_get_set_delete
echo "Testing _nvm_cache_set, _nvm_cache_get, and _nvm_cache_delete..."
set -l key test_key
set -l value test_value
# Set cache value
_nvm_cache_set $key $value
set -l result (_nvm_cache_get $key 300)
assert_equals "$result" "$value" "Cache set and get returns correct value"
# Delete cache value
_nvm_cache_delete $key
set -l result (_nvm_cache_get $key 300)
set -l status_code $status
test $status_code -ne 0
and echo "✅ Cache delete works"
or echo "❌ Cache delete failed"
return 0
end
function test_nvm_cache_clear_and_stats
echo "Testing _nvm_cache_clear and _nvm_cache_stats..."
# Set multiple cache values
_nvm_cache_set key1 value1
_nvm_cache_set key2 value2
# Stats should show at least 2 files
set -l stats (_nvm_cache_stats)
assert_contains "$stats" "Cache files:" "Cache stats reports file count"
# Clear cache
_nvm_cache_clear
set -l stats_after (_nvm_cache_stats)
assert_contains "$stats_after" "Cache files: 0" "Cache clear removes all files"
return 0
end
function test_nvm_cache_ttl
echo "Testing _nvm_cache_get TTL expiration..."
set -l key ttl_key
set -l value ttl_value
_nvm_cache_set $key $value
# Should exist immediately
set -l result (_nvm_cache_get $key 10)
assert_equals "$result" "$value" "Cache value exists within TTL"
# Simulate expired cache by setting TTL to 0
set -l result (_nvm_cache_get $key 0)
set -l status_code $status
test $status_code -ne 0
and echo "✅ Cache TTL expiration works"
or echo "❌ Cache TTL expiration failed"
_nvm_cache_delete $key
return 0
end
function test_nvm_cache_dir
echo "Testing _nvm_cache_dir returns a valid directory..."
set -l dir (_nvm_cache_dir)
test -n "$dir"
and echo "✅ _nvm_cache_dir returns: $dir"
or echo "❌ _nvm_cache_dir did not return a directory"
return 0
end
function main
set -l failed 0
test_nvm_cache_get_set_delete; or set failed (math "$failed + 1")
test_nvm_cache_clear_and_stats; or set failed (math "$failed + 1")
test_nvm_cache_ttl; or set failed (math "$failed + 1")
test_nvm_cache_dir; or set failed (math "$failed + 1")
if test $failed -eq 0
echo "🎉 All nvm_cache helper tests passed!"
return 0
else
echo "💥 $failed nvm_cache helper test(s) failed"
return 1
end
end
main

154
tests/unit/test_security.fish Executable file
View File

@@ -0,0 +1,154 @@
#!/usr/bin/env fish
# Unit tests for nvm_security.fish
source tests/test_runner.fish
function test_version_validation
echo "Testing version validation..."
# Valid versions
nvm_security check_version "18.17.0"
and echo "✅ Valid semver accepted"
or echo "❌ Valid semver rejected"
nvm_security check_version "v20.5.1"
and echo "✅ Version with 'v' prefix accepted"
or echo "❌ Version with 'v' prefix rejected"
# Invalid versions
nvm_security check_version "invalid.version"
set -l status_code $status
test $status_code -ne 0
and echo "✅ Invalid version rejected"
or echo "❌ Invalid version accepted"
# Suspicious characters
nvm_security check_version "18.0.0; touch /tmp/nvm-auto-use-malicious-test"
set status_code $status
test $status_code -ne 0
and echo "✅ Malicious version string rejected"
or echo "❌ Malicious version string accepted"
return 0
end
function test_security_policies
echo "Testing security policies..."
# Set minimum version policy
nvm_security policy set min_version "16.0.0"
set -l min_version (nvm_security policy get min_version)
assert_equals "$min_version" "16.0.0" "Minimum version policy set correctly"
# Test version below minimum
nvm_security check_version "14.0.0"
set -l status_code $status
test $status_code -ne 0
and echo "✅ Version below minimum rejected"
or echo "❌ Version below minimum accepted"
# Set maximum version policy
nvm_security policy set max_version "20.0.0"
set -l max_version (nvm_security policy get max_version)
assert_equals "$max_version" "20.0.0" "Maximum version policy set correctly"
# Test version above maximum
nvm_security check_version "21.0.0"
set status_code $status
test $status_code -ne 0
and echo "✅ Version above maximum rejected"
or echo "❌ Version above maximum accepted"
# Reset policies
nvm_security policy reset
return 0
end
function test_version_comparison
echo "Testing version comparison..."
# Test less than
_nvm_security_version_compare "16.0.0" "18.0.0" -lt
and echo "✅ Version comparison (less than) works"
or echo "❌ Version comparison (less than) failed"
# Test greater than
_nvm_security_version_compare "20.0.0" "18.0.0" -gt
and echo "✅ Version comparison (greater than) works"
or echo "❌ Version comparison (greater than) failed"
# Test equal
_nvm_security_version_compare "18.17.0" "18.17.0" -eq
and echo "✅ Version comparison (equal) works"
or echo "❌ Version comparison (equal) failed"
return 0
end
function test_source_validation
echo "Testing source file validation..."
# Create test files
echo "18.17.0" >test_nvmrc
echo "18.0.0; touch /tmp/nvm-auto-use-malicious-test" >malicious_nvmrc
# Test valid source
nvm_security validate_source test_nvmrc
and echo "✅ Valid source file accepted"
or echo "❌ Valid source file rejected"
# Test malicious source
nvm_security validate_source malicious_nvmrc
set -l status_code $status
test $status_code -ne 0
and echo "✅ Malicious source file rejected"
or echo "❌ Malicious source file accepted"
# Cleanup
rm -f test_nvmrc malicious_nvmrc
return 0
end
function test_vulnerability_check
echo "Testing vulnerability checking..."
# Test known vulnerable version (if any in our test data)
nvm_security check_cve "16.0.0"
set -l status_code $status
test $status_code -ne 0
and echo "✅ Known vulnerable version flagged"
or echo " No vulnerability data for test version"
# Test presumably safe version
nvm_security check_cve "18.17.0"
and echo "✅ Safe version check completed"
or echo " Vulnerability check completed with warnings"
return 0
end
function main
setup_test_env
set -l failed 0
test_version_validation; or set failed (math "$failed + 1")
test_security_policies; or set failed (math "$failed + 1")
test_version_comparison; or set failed (math "$failed + 1")
test_source_validation; or set failed (math "$failed + 1")
test_vulnerability_check; or set failed (math "$failed + 1")
cleanup_test_env
if test $failed -eq 0
echo "🎉 All security tests passed!"
return 0
else
echo "💥 $failed security test(s) failed"
return 1
end
end
main