Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,72 @@ Conventions used across the codebase:
- Output and security language must be precise. Avoid words like "fully safe", "guaranteed compatible", or "stable version" in user-visible text. Findings are based on advisory data, not exploitability or runtime reachability claims.
- Every finding should aim to produce a runnable command where the data supports it. Vague guidance like "upgrade the parent dependency chain" without naming the parent is treated as a regression.

### Named constants

Magic strings and numbers must not be inlined. Extract them to named constants in `src/constants.ts`:

```typescript
// bad
const results = await queryOsv(packages, 100);

// good
import { DEFAULT_BATCH_SIZE } from "./constants.js";
const results = await queryOsv(packages, DEFAULT_BATCH_SIZE);
```

This applies to repeated flag strings, batch sizes, cache TTLs, depth limits, and any other value that has a name or meaning beyond its raw literal.

### DRY

Repeated logic belongs in a shared utility, not copied across files. If the same string literal, function body, or conditional pattern appears in two or more places, extract it:

- Repeated string literals - extract to a constant
- Repeated utility functions - extract to the appropriate module under `src/utils/`
- Repeated output formatting logic - extract to `src/output/formatters.ts`

Pull requests that duplicate existing logic are asked to consolidate before merge.

### File size and single responsibility

Each file should have one clear purpose. If you cannot describe what a file does in one sentence, it is doing too much.

Keep files focused and small. When a file grows large, extract shared logic into a dedicated utility module rather than continuing to add to it. This applies especially to `src/index.ts`, which is the entry point and should remain a thin orchestration layer.

New output formats (JSON, SARIF, HTML, CycloneDX) each get their own dedicated module following the `html-reporter.ts` pattern. Do not add a new format to an existing formatter file.

Display logic, hint text, and error messages belong in utility modules (`src/utils/`, `src/output/`), not inlined in `src/index.ts`.

### Braces on conditionals

All `if`, `else`, `for`, and `while` blocks must use braces, even for single-line bodies:

```typescript
// bad
if (condition) doSomething();

// good
if (condition) {
doSomething();
}
```

### Formatting

Code is formatted with [Prettier](https://prettier.io). Run the formatter before opening a pull request:

```bash
npm run format
```

CI will reject pull requests where files are not formatted. The project config is in `.prettierrc` at the repo root.

What gets pushed back during review:

- Refactors bundled into feature work or bug fixes. Open a separate issue and pull request.
- Defensive error handling for cases that cannot occur. Trust internal invariants; only validate at system boundaries (user input, external APIs, file I/O).
- Unsupportable claims in commit messages, release notes, or output text. Commit messages must be factual and scoped to the diff.
- Magic strings or numbers inlined in source code instead of named constants.
- Duplicated logic that already exists in a shared utility.

## Setup

Expand Down