Skip to content

Contributing to Unreach ​

Thank you for your interest in contributing to Unreach! This document provides guidelines and instructions for contributing to the project.

Code of Conduct ​

This project adheres to a code of conduct that all contributors are expected to follow. Please be respectful, inclusive, and constructive in all interactions.

Getting Started ​

Prerequisites ​

  • Node.js: Version 18.0.0 or higher
  • npm: Package manager
  • Git: Version control

Fork and Clone ​

  1. Fork the repository on GitHub

  2. Clone your fork:

    bash
    git clone https://github.com/kiron0/unreach.git
    cd unreach
  3. Add the upstream repository:

    bash
    git remote add upstream https://github.com/kiron0/unreach.git

Development Setup ​

1. Install Dependencies ​

bash
npm install

2. Build the Project ​

bash
npm run build

This compiles TypeScript to JavaScript in the dist/ directory.

3. Run in Development Mode ​

bash
# Build and watch for changes
npm run build:watch

# In another terminal, run the CLI
node dist/index.js scan
bash
# Build first
npm run build

# Link globally (allows using 'unreach' command)
npm link

Now you can use unreach command from anywhere to test your changes.

Project Structure ​

package/
├── src/
│   ├── cli/              # CLI interface (args, handler, ui, interactive)
│   ├── core/             # Core error handling
│   ├── lib/              # Core library code
│   │   ├── analyzer/     # Analysis logic (finders, reachability)
│   │   ├── cache.ts      # Caching system
│   │   ├── config.ts     # Configuration loading
│   │   ├── graph.ts      # Dependency graph builder
│   │   ├── parser.ts     # AST parser
│   │   └── ...
│   ├── types/            # TypeScript type definitions
│   └── utils/            # Utility functions
├── dist/                 # Compiled output (generated)
├── reports/              # Documentation and analysis reports
├── tests/                # Test files (co-located with source)
└── package.json

Key Components ​

  • Parser (src/lib/parser.ts): Parses TypeScript/JavaScript files into AST
  • Graph Builder (src/lib/graph.ts): Builds dependency graph from parsed files
  • Analyzer (src/lib/analyzer/): Performs reachability analysis and finds unused code
  • CLI (src/cli/): Command-line interface and user interaction

Code Style Guidelines ​

TypeScript ​

  • Strict Mode: The project uses strict TypeScript settings
  • Type Safety: Avoid any types. Use proper types or unknown with type guards
  • Naming Conventions:
    • Classes: PascalCase (e.g., DependencyGraph)
    • Functions/Variables: camelCase (e.g., parseFile)
    • Constants: UPPER_SNAKE_CASE (e.g., MAX_FILE_SIZE)
    • Files: kebab-case.ts (e.g., config-loader.ts)

Formatting ​

The project uses Prettier for code formatting:

bash
# Format all files
npm run format

# Or format specific files
npx prettier --write "src/**/*.ts"

Code Organization ​

  • Single Responsibility: Each file/class should have one clear purpose
  • Modular Design: Keep functions small and focused
  • Error Handling: Use the UnreachError class for consistent error handling
  • Comments: Add JSDoc comments for public APIs

Example Code Style ​

typescript
/**
 * Parses a TypeScript file and extracts dependency information.
 * @param filePath - Path to the file to parse
 * @param useCache - Whether to use cached AST if available
 * @returns Dependency node or null if parsing fails
 */
export function parseFile(
  filePath: string,
  useCache: boolean = true,
): DependencyNode | null {
  // Implementation
}

Import Organization ​

  1. External dependencies (npm packages)
  2. Internal modules (from src/)
  3. Type imports (use import type when possible)
typescript
import chalk from "chalk";
import * as fs from "fs";
import * as path from "path";

import type { DependencyNode } from "../types/index.js";
import { ASTParser } from "./parser.js";

Testing ​

Running Tests ​

bash
# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with UI
npm run test:ui

# Run tests with coverage
npm run test:coverage

Test Structure ​

Tests are co-located with source files:

  • Source: src/lib/config.ts
  • Test: src/lib/config.test.ts

Writing Tests ​

  • Use Vitest as the testing framework
  • Follow the describe → it structure
  • Use descriptive test names
  • Test both happy paths and edge cases

Example Test:

typescript
import { describe, expect, it } from "vitest";
import { ConfigLoader } from "./config.js";

describe("ConfigLoader", () => {
  it("should load configuration file", () => {
    // Arrange
    const loader = new ConfigLoader("./test-fixtures");

    // Act
    const config = loader.load();

    // Assert
    expect(config).not.toBeNull();
    expect(config?.ignore?.files).toContain("**/*.test.ts");
  });
});

Test Coverage ​

  • Aim for high test coverage, especially for core functionality
  • Test edge cases and error conditions
  • Use beforeEach and afterEach for test setup/cleanup
  • Mock external dependencies when appropriate

Test Requirements ​

  • ✅ All tests must pass before submitting a PR
  • ✅ New features should include tests
  • ✅ Bug fixes should include regression tests
  • ✅ Tests should be fast and isolated

Making Changes ​

1. Create a Branch ​

bash
git checkout -b feature/your-feature-name
# or
git checkout -b fix/your-bug-fix

2. Make Your Changes ​

  • Write clean, well-documented code
  • Follow the code style guidelines
  • Add tests for new functionality
  • Update documentation if needed

3. Commit Your Changes ​

Use clear, descriptive commit messages:

bash
git commit -m "feat: add file size limit configuration"
git commit -m "fix: resolve config validation error"
git commit -m "test: add tests for watch mode rate limiting"

Commit Message Format:

  • feat: - New feature
  • fix: - Bug fix
  • test: - Adding or updating tests
  • docs: - Documentation changes
  • refactor: - Code refactoring
  • perf: - Performance improvements
  • chore: - Maintenance tasks

4. Keep Your Branch Updated ​

bash
# Fetch latest changes
git fetch upstream

# Rebase your branch on main
git rebase upstream/main

Pull Request Process ​

Before Submitting ​

  1. ✅ All tests pass: Run npm test
  2. ✅ Code is formatted: Run npm run format
  3. ✅ Build succeeds: Run npm run build
  4. ✅ No linter errors: Check for TypeScript errors
  5. ✅ Documentation updated: Update relevant docs if needed

Creating a Pull Request ​

  1. Push your branch:

    bash
    git push origin feature/your-feature-name
  2. Create PR on GitHub:

    • Go to the repository on GitHub
    • Click "New Pull Request"
    • Select your branch
    • Fill out the PR template

PR Description Template ​

markdown
## Description

Brief description of changes

## Type of Change

- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Testing

- [ ] Tests added/updated
- [ ] All tests pass
- [ ] Manual testing completed

## Checklist

- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code
- [ ] Documentation updated
- [ ] No new warnings generated

PR Review Process ​

  1. Automated Checks: CI will run tests and checks
  2. Code Review: Maintainers will review your code
  3. Feedback: Address any requested changes
  4. Approval: Once approved, your PR will be merged

After PR is Merged ​

  • Your branch can be deleted
  • Update your local main branch: git pull upstream main

Reporting Issues ​

Before Reporting ​

  1. Check if the issue already exists
  2. Try to reproduce the issue
  3. Check the documentation

Issue Template ​

When creating an issue, include:

  • Description: Clear description of the issue
  • Steps to Reproduce: How to reproduce the issue
  • Expected Behavior: What should happen
  • Actual Behavior: What actually happens
  • Environment: Node.js version, OS, etc.
  • Screenshots/Logs: If applicable

Bug Reports ​

markdown
**Describe the bug**
A clear description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:

1. Run 'unreach scan ...'
2. See error

**Expected behavior**
What you expected to happen.

**Environment:**

- Node.js version: [e.g., 18.0.0]
- OS: [e.g., macOS 14.0]
- Unreach version: [e.g., 0.1.0]

**Additional context**
Any other relevant information.

Development Tips ​

Debugging ​

  • Use --debug flag for detailed error information
  • Use --verbose flag for detailed processing logs
  • Use Node.js debugger: node --inspect dist/index.js scan

Common Tasks ​

Adding a new finder (e.g., unused interfaces):

  1. Create src/lib/analyzer/finders/interface-finder.ts
  2. Implement the finder logic
  3. Export from src/lib/analyzer/finders/index.ts
  4. Add to src/lib/analyzer/index.ts
  5. Add tests

Adding a new CLI option:

  1. Add option to src/cli/args.ts
  2. Add to ScanOptions in src/types/index.ts
  3. Implement logic in src/cli/handler.ts
  4. Update help text in src/cli/ui.ts
  5. Add tests

Adding configuration option:

  1. Add to UnreachConfig in src/lib/config.ts
  2. Add validation in validateConfig()
  3. Add default in mergeWithDefaults()
  4. Update documentation
  5. Add tests

Getting Help ​

  • Documentation: Check reports/ directory for detailed docs
  • Issues: Search existing issues on GitHub
  • Discussions: Use GitHub Discussions for questions

License ​

By contributing, you agree that your contributions will be licensed under the MIT License.


Thank you for contributing to Unreach! 🎉

Released under the MIT License.