UNPKG

@boilerbuilder/deps-analyzer

Version:

CLI tool to analyze dependency evolution and release frequency

577 lines (451 loc) 17.7 kB
# Dependencies Evolution Analyzer 📊 Advanced CLI tool to analyze dependency evolution, release frequency, and semver patterns in JavaScript/Node.js projects. ## Features - 🔍 **Auto-discovery**: Finds package.json files in directories or glob patterns - 📊 **NPM Analysis**: Fetches release data from NPM registry with smart filtering - 🏷️ **Semver Analysis**: Detailed breakdown of major/minor/patch releases - 📅 **Time-based Analysis**: Compares releases from different time periods (12m vs 12-24m) - 📄 **Multiple Outputs**: Generates both JSON and Markdown reports - 🚀 **Multiple Projects**: Analyze multiple patterns/projects in one command - **Fast**: Built-in NPM CLI integration and efficient processing - 🛡️ **Robust**: Handles errors gracefully and continues processing - 🔧 **Smart Filtering**: Automatically filters dev/beta/alpha/nightly versions ## Installation ### Local Development ```bash git clone <repository-url> cd deps-analyzer npm install ``` ### Using npm link for testing ```bash npm run link # Link globally for testing deps-analyzer --help # Test the command npm run unlink # Unlink when done ``` ## 📚 Documentation For detailed information on specific topics: - **[Libyear Algorithm](docs/libyears.md)** - Understanding drift/pulse metrics and calculations - **[Max-Deps Configuration](docs/max-deps.md)** - Strategic version control and constraints - **[NPM Client](docs/npm-client.md)** - Data collection strategies and filtering - **[Report Interpretation](docs/reporter.md)** - How to read and act on analysis results ## Usage ### Basic Usage ```bash # Analyze templates directory deps-analyzer ./templates # Analyze single project deps-analyzer ./package.json # Use glob patterns deps-analyzer "projects/**/package.json" ``` ### Multiple Projects ```bash # Analyze specific projects deps-analyzer templates/next-app templates/react-spa-vite --output selected-projects # Mix directories and files deps-analyzer ./frontend ./backend/package.json --output fullstack-analysis ``` ### Advanced Options ```bash # Custom analysis period deps-analyzer ./templates --months 18 # Custom output name deps-analyzer ./templates --output my-report # Skip NPM analysis (discovery only) deps-analyzer ./templates --no-npm # Use HTTP instead of npm CLI (slower but more compatible) deps-analyzer ./templates --use-http # Advanced filtering for internal libraries deps-analyzer ./templates --internal-libs "@akad/*,design-system*" # Skip specific version filters deps-analyzer ./templates --ignore-filter alpha,beta,rc # Combined enterprise usage deps-analyzer ./templates --internal-libs "@company/*" --ignore-filter canary,nightly # Custom max-deps configuration file deps-analyzer ./templates --max-deps-config ./my-constraints.json # Strategic version control example echo '{"react": "^18.0.0", "typescript": "^5.0.0"}' > max-deps.json deps-analyzer ./project --max-deps-config max-deps.json # Help and version deps-analyzer --help deps-analyzer --version ``` ### Scope Filtering Analyze only internal or external dependencies using `--scope`: ```bash # Analyze only internal dependencies deps-analyzer ./templates --scope=internal --internal-libs "@company/*" # Analyze only external dependencies (excludes internal) deps-analyzer ./templates --scope=external --internal-libs "@company/*" # Analyze all dependencies (default behavior) deps-analyzer ./templates --scope=all --internal-libs "@company/*" ``` ### Max-Deps Configuration Examples Strategic version control with custom configuration files: ```bash # Production environment constraints deps-analyzer ./templates --max-deps-config ./configs/production.json # Shared team constraints deps-analyzer ./templates --max-deps-config /shared/team-constraints.json # Benchmark analysis (zero-drift simulation) deps-analyzer ./templates --max-deps-config ./benchmarks/zero-drift.json --output benchmark # Enterprise compliance analysis deps-analyzer ./microservices --max-deps-config ./security/approved-versions.json ``` ## Output The tool generates two files with comprehensive analysis: ### JSON Report (`<output>.json`) ```json { "metadata": { "generatedAt": "2025-08-14T00:26:31.877Z", "period": "24 months", "totalProjects": 2, "totalDependencies": 52, "uniqueDependencies": 36, "globalUniqueReleases": { "totalLast12m": 1130, "totalLast12to24m": 983, "avgPerMonthLast12m": 94.17, "avgPerMonthLast12to24m": 81.92, "semverBreakdown": { "majorLast12m": 26, "minorLast12m": 165, "patchLast12m": 597, "avgMajorPerMonthLast12m": 2.17, "avgMinorPerMonthLast12m": 13.75, "avgPatchPerMonthLast12m": 49.75 } } }, "projects": { "react-spa-vite": { "packagePath": "/path/to/package.json", "dependencyCount": 32, "dependencies": { "react": { "currentVersion": "19.1.1", "last12Months": 3, "months12to24": 2, "totalReleases": 345, "avgReleasesPerMonthLast12m": 0.25, "avgReleasesPerMonthLast12to24m": 0.17, "avgDaysBetweenReleases": 14.6, "semverBreakdown": { "majorLast12m": 1, "minorLast12m": 1, "patchLast12m": 1, "majorLast12to24m": 0, "minorLast12to24m": 1, "patchLast12to24m": 1 }, "monthlyBreakdown": { "2024-12": ["19.0.0"], "2025-03": ["19.1.0"], "2025-07": ["19.1.1"] }, "mostActiveMonth": "2024-12 (1)" } }, "metadata": { "totalReleasesLast12m": 672, "totalReleasesLast12to24m": 655, "totalReleases": 6429, "avgReleasesPerMonthLast12m": 56, "avgReleasesPerMonthLast12to24m": 54.58, "semverBreakdown": { "totalMajorLast12m": 22, "totalMinorLast12m": 140, "totalPatchLast12m": 419, "avgMajorPerMonthLast12m": 1.83, "avgMinorPerMonthLast12m": 11.67, "avgPatchPerMonthLast12m": 34.92 } } } } } ``` ### Markdown Report (`<output>.md`) ```markdown # Dependencies Evolution Report ## Summary - **Generated at:** 2025-08-14 00:26:31 UTC - **Analysis period:** 24 months - **Projects analyzed:** 2 - **Total dependencies:** 52 - **Unique dependencies:** 36 ## Global Statistics - **Total releases (12m):** 1,130 (avg: 94.17/month) - **Total releases (12-24m):** 983 (avg: 81.92/month) - **Semver breakdown (12m):** 26 major, 165 minor, 597 patch ## Project: react-spa-vite (32 dependencies) ### Dependencies Release Activity (Last 12m vs 12-24m) | Package | Current | 12m | 12-24m | Major | Minor | Patch | Most Active Month | |---------|---------|-----|--------|-------|-------|-------|-------------------| | react | 19.1.1 | 3 | 2 | 1 | 1 | 1 | 2024-12 (1) | ``` ## API ### Programmatic Usage ```javascript const { main } = require('deps-analyzer'); // Basic analysis const result = await main(['./templates']); // Multiple patterns const result = await main([ './templates/next-app', './templates/react-spa-vite' ]); // With options const result = await main(['./templates'], { months: 18, output: 'custom-report', analyzeNpm: true, useNpmCli: true }); ``` ## Options Reference | Option | Default | Description | |--------|---------|-------------| | `--months <number>` | `24` | Analysis period in months | | `--output <path>, -o` | `dependency-report` | Output file base name | | `--scope <type>` | `all` | Filter dependencies by scope: internal, external, all | | `--no-npm` | `false` | Skip NPM registry analysis (discovery only) | | `--use-http` | `false` | Use HTTP requests instead of npm CLI (slower) | | `--ignore-filter <list>` | `[]` | Skip filtering specific version types (alpha,beta,rc,etc) | | `--internal-libs <list>` | `[]` | Libraries to include alpha/beta versions (supports wildcards: @akad/*,design-system*) | | `--max-deps-config <path>` | `null` | Custom max-deps.json file path for strategic version control | | `--help, -h` | - | Show help information | | `--version, -v` | - | Show version | ## Examples ### Template Repository Analysis ```bash # Analyze all templates deps-analyzer ./templates --months 12 --output templates-report # Analyze specific templates deps-analyzer templates/next-app templates/react-spa-vite --output selected-templates ``` ### Monorepo Analysis ```bash # Analyze all packages deps-analyzer "packages/*/package.json" --months 18 # Analyze specific workspaces deps-analyzer packages/frontend packages/backend packages/shared --output monorepo-analysis ``` ### Quick Dependency Discovery ```bash # Skip NPM analysis for faster results deps-analyzer ./project --no-npm # Discovery only with HTTP fallback deps-analyzer ./project --no-npm --use-http ``` ### Enterprise Usage ```bash # Comprehensive analysis with custom period deps-analyzer ./microservices ./shared-libs --months 36 --output enterprise-deps ``` ## Advanced Filtering ### Filtering Strategy Hierarchy The tool applies filtering in a specific order to ensure predictable results: 1. **Scope Filtering** (`--scope`): First, filter dependencies by scope (internal, external, all) 2. **Internal Library Classification** (`--internal-libs`): Classify remaining dependencies as internal/external 3. **Selective Version Filtering**: Apply different filtering rules based on classification 4. **Filter Overrides** (`--ignore-filter`): Override specific version type filtering ### Internal vs External Dependencies The tool implements **selective filtering** that treats internal and external dependencies differently: - **External Dependencies**: Automatically filters out pre-release versions (alpha, beta, rc, etc.) - **Internal Dependencies**: Can include pre-release versions when specified via `--internal-libs` ### Scope Filtering Behavior - **`--scope=internal`**: Analyze only dependencies matching `--internal-libs` patterns - **`--scope=external`**: Analyze only dependencies NOT matching `--internal-libs` patterns - **`--scope=all`**: Analyze all dependencies (default), but still apply selective filtering logic ### Pattern Matching The `--internal-libs` flag supports wildcard patterns: ```bash # Exact match deps-analyzer ./project --internal-libs "my-package" # Scoped packages with wildcard deps-analyzer ./project --internal-libs "@company/*" # Multiple patterns deps-analyzer ./project --internal-libs "@company/*,design-system*,@internal/*" ``` ### Filtering Override Use `--ignore-filter` to skip specific version type filtering: ```bash # Include alpha versions for ALL dependencies deps-analyzer ./project --ignore-filter alpha # Include multiple pre-release types deps-analyzer ./project --ignore-filter alpha,beta,rc # Combined usage: include alpha/beta for internal libs only deps-analyzer ./project --internal-libs "@company/*" --ignore-filter canary,nightly ``` ### Practical Examples #### Enterprise Monorepo Analysis ```bash # Analyze with company-specific internal libraries deps-analyzer ./packages/* \ --internal-libs "@acme/*,design-tokens*" \ --ignore-filter canary \ --output enterprise-analysis ``` #### Mixed Public/Private Dependencies ```bash # Allow alpha/beta for internal libs, strict filtering for external deps-analyzer ./apps/frontend ./apps/backend \ --internal-libs "@company/*,internal-*" \ --output mixed-dependencies ``` #### Historical Analysis with Custom Filters ```bash # Skip all pre-release filtering for specific analysis deps-analyzer ./legacy-projects \ --ignore-filter alpha,beta,rc,canary,experimental \ --output legacy-comprehensive ``` ## Understanding the Output ### Portfolio vs Project Metrics The tool provides **two different types of drift/pulse calculations** that serve different purposes: #### 🏢 Global/Portfolio Metrics (Unique Dependencies) - **What it measures**: Drift/pulse for each dependency **once per portfolio** - **Calculation**: Sums drift only from unique dependencies across all projects - **Example**: If `react` appears in 4 projects, its drift is counted **only once** - **Use case**: Strategic decisions - "Which dependencies should we prioritize updating?" #### 📋 Project Metrics (Total Across Projects) - **What it measures**: Drift/pulse for **every occurrence** of each dependency - **Calculation**: Sums drift from all dependencies in all projects - **Example**: If `react` appears in 4 projects, its drift is counted **4 times** - **Use case**: Effort estimation - "How much total work is needed to update everything?" #### 💡 Example: 4 Projects with React (2y drift) **Scenario:** - 4 projects each use `react` with 2 years of drift - Each project also has `lodash` with 1 year of drift **Global Drift (Unique Dependencies):** - `react`: 2 years (counted once) - `lodash`: 1 year (counted once) - **Total: 3 years** **Project Drift (Sum Across Projects):** - Project 1: `react` (2y) + `lodash` (1y) = 3y - Project 2: `react` (2y) + `lodash` (1y) = 3y - Project 3: `react` (2y) + `lodash` (1y) = 3y - Project 4: `react` (2y) + `lodash` (1y) = 3y - **Total: 12 years** #### 🎯 When to Use Each Metric | Scenario | Use Global Metrics | Use Project Metrics | |----------|-------------------|-------------------| | Prioritizing which deps to update | Focus on unique deps | May mislead priorities | | Estimating update effort/time | Underestimates work | Shows true scope | | Executive reporting | Clear strategic view | May seem inflated | | Sprint planning | Doesn't show full work | Shows actual tasks | | Ecosystem health assessment | True portfolio state | Duplicated concerns | ### Semver Analysis The tool performs intelligent semver analysis: - **Major**: Breaking changes (1.0.0 2.0.0) - **Minor**: New features (1.0.0 1.1.0) - **Patch**: Bug fixes (1.0.0 1.0.1) ### Smart Filtering Automatically filters out: - Development versions (`-dev`, `-nightly`) - Alpha/Beta releases (`-alpha`, `-beta`) - Release candidates (`-rc`) - Experimental builds (`-experimental`, `-canary`) - Malformed versions (`0.0.0-*`) ### Backport Detection The tool detects version backports/downgrades: - Total releases include all stable versions - Semver breakdown only counts progressive releases - Difference represents maintenance releases for older versions ## Technical Details - **Rate Limiting**: Intelligent batching with NPM CLI - **Error Handling**: Continues processing even if some packages fail - **Ignores**: `node_modules/`, `public/`, `dist/`, `build/` directories - **Node Version**: Requires Node.js >= 16.0.0 - **NPM Version**: Works with npm >= 7.0.0 ## Development ### Project Structure ``` deps-analyzer/ ├── package.json ├── README.md ├── bin/ └── deps-analyzer.js # CLI entry point ├── lib/ ├── index.js # Core logic & discovery ├── npm-client.js # NPM registry client ├── libyear.js # Drift/pulse calculations └── reporter.js # Report generation └── utils/ # Utility functions ├── chunkArray.js # Array chunking ├── cleanVersion.js # Version cleaning ├── filterDependenciesByScope.js # Dependency filtering ├── findMaxAllowedVersion.js # Version constraint parsing ├── findWorkspaceRoot.js # Workspace detection ├── isInternalLib.js # Internal library matching ├── parsePnpmLock.js # PNPM lock file parsing ├── parseYarnLock.js # Yarn lock file parsing └── versionSatisfiesConstraint.js # Semver constraint checking ``` ### Scripts ```bash npm run start # Run with default args npm run test # Test with templates npm run dev # Run with debugging npm run link # Link globally npm run unlink # Unlink globally ``` ### Debugging ```bash # Enable detailed error information DEBUG=1 deps-analyzer ./templates # Use HTTP instead of npm CLI if issues deps-analyzer ./templates --use-http ``` ## Troubleshooting ### Common Issues **npm CLI not found** ```bash # Use HTTP fallback deps-analyzer ./templates --use-http ``` **Permission errors** ```bash # Check npm permissions npm config get prefix npm config get cache ``` **Network timeouts** ```bash # Increase npm timeout npm config set timeout 60000 deps-analyzer ./templates ``` **Memory issues with large projects** ```bash # Analyze projects separately deps-analyzer ./project1 --output report1 deps-analyzer ./project2 --output report2 ``` ## Performance ### Benchmarks - **Small project** (10 deps): ~2-5 seconds - **Medium project** (50 deps): ~10-20 seconds - **Large monorepo** (200+ deps): ~1-3 minutes ### Optimization Tips - Use npm CLI mode (default) for better performance - Analyze fewer projects simultaneously for large codebases - Use `--no-npm` for quick dependency discovery ## License MIT ## Contributing 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'Add some amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Create a Pull Request ### Development Guidelines - Maintain backward compatibility - Add tests for new features - Update documentation - Follow existing code style --- Built with ❤️ for better dependency management and DevOps insights