mirror of
https://github.com/ivuorinen/nvm-auto-use.fish.git
synced 2026-01-26 11:14:03 +00:00
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:
@@ -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": []
|
||||
}
|
||||
}
|
||||
@@ -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
50
.github/install_editorconfig-checker.sh
vendored
Executable 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!"
|
||||
15
.github/workflows/pr-lint.yml
vendored
15
.github/workflows/pr-lint.yml
vendored
@@ -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
1
.gitignore
vendored
@@ -22,3 +22,4 @@
|
||||
*~
|
||||
Session.vim
|
||||
Sessionx.vim
|
||||
.claude/settings.local.json
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
"MD013": { "line_length": 120 },
|
||||
"MD033": false,
|
||||
"MD041": false
|
||||
}
|
||||
}
|
||||
|
||||
116
CLAUDE.md
116
CLAUDE.md
@@ -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
|
||||
|
||||
90
Makefile
90
Makefile
@@ -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!"
|
||||
|
||||
90
README.md
90
README.md
@@ -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
106
functions/nvm_async.fish
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
110
functions/nvm_cache.fish
Normal 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
|
||||
@@ -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
428
functions/nvm_doctor.fish
Normal 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
|
||||
168
functions/nvm_error_recovery.fish
Normal file
168
functions/nvm_error_recovery.fish
Normal 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
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
354
functions/nvm_recommendations.fish
Normal file
354
functions/nvm_recommendations.fish
Normal 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
278
functions/nvm_security.fish
Normal 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
|
||||
@@ -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
|
||||
|
||||
178
tests/integration/test_version_switching.fish
Executable file
178
tests/integration/test_version_switching.fish
Executable 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
189
tests/test_runner.fish
Executable 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
|
||||
109
tests/unit/test_async_helpers.fish
Normal file
109
tests/unit/test_async_helpers.fish
Normal 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
|
||||
109
tests/unit/test_auto_use_config_helpers.fish
Normal file
109
tests/unit/test_auto_use_config_helpers.fish
Normal 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
|
||||
134
tests/unit/test_auto_use_helpers.fish
Normal file
134
tests/unit/test_auto_use_helpers.fish
Normal 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
98
tests/unit/test_cache.fish
Executable 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
|
||||
99
tests/unit/test_cache_helpers.fish
Normal file
99
tests/unit/test_cache_helpers.fish
Normal 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
154
tests/unit/test_security.fish
Executable 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
|
||||
Reference in New Issue
Block a user