From 99dcd0c6eb17f2f2da9f7ff330cdbe52cfa40554 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor Date: Tue, 26 May 2026 09:15:00 -0400 Subject: [PATCH] docs: expand CONTRIBUTING.md with code quality standards Add named constants, DRY, single responsibility, braces on conditionals, and formatting sections to the coding standards. Closes #445 --- src/docs/CONTRIBUTING.md | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/docs/CONTRIBUTING.md b/src/docs/CONTRIBUTING.md index a9931e5..af3f564 100644 --- a/src/docs/CONTRIBUTING.md +++ b/src/docs/CONTRIBUTING.md @@ -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