ngcompass

Reference

Baseline.

Enabling a full preset on an existing codebase reports every violation it already has. A baseline records those once so analyze reports only what is new, letting you keep the rules on without clearing the backlog first.

How it works

The baseline is a JSON file, committed with your code, holding a violation count per file per rule. When applied, a run hides violations up to the recorded count and reports everything else normally.

The alternative — switching rules to off until the backlog clears — also stops them protecting the code you write tomorrow. A baseline keeps the gate on new code while the existing violations wait.

Create one

bash
01npx ngcompass baseline create
01❯ Running a full analysis for the baseline...
02❯ Baseline written: .ngcompass/baseline.json
03 6 violations recorded across 3 files (2 rules scanned)

Commit .ngcompass/baseline.json. It describes the state of the code next to it, so it belongs in version control and should move in the same pull request as any change that alters it.

Apply it

bash
01# Uses baseline.path from config
02npx ngcompass analyze --baseline
03
04# Explicit file
05npx ngcompass analyze --baseline .ngcompass/baseline.json
06
07# Ignore a baseline that config enables
08npx ngcompass analyze --no-baseline

Hidden violations stay in the summary line, so a green run still reports the size of the backlog:

01❯ src/fresh.component.ts:4:22
02
03 ❯ 4 | template: '<ul><li *ngFor="let x of items">{{ x }}</li></ul>',
04 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
05
06× 1 violation (1 error, 0 warnings) FAILED · 6 hidden by baseline

The HTML report shows the same count as a Hidden by baseline stat. If the baseline is enabled and the file is missing, the run fails with a message pointing at baseline create rather than analyzing without it.

The file

.ngcompass/baseline.json
01{
02 "version": 1,
03 "entries": {
04 "src/legacy.component.ts": {
05 "template-prefer-control-flow": 2
06 },
07 "src/widget.component.ts": {
08 "template-prefer-control-flow": 2
09 }
10 }
11}

Counts, not fingerprints — no line numbers, no message hashes, no copies of your source. Reformatting a file or moving code within it does not invalidate an entry. Files and rules are written sorted and zero counts are dropped, so diffs stay readable.

The trade-off is precision: a file recorded at 2 hides any 2 violations of that rule, not specifically the 2 that were there when you recorded it. Prune regularly and the window stays small.

As the code changes

  • A new violation is added

    Reported, and the run exits non-zero as usual. A file recorded with 2 violations of a rule hides 2 — the third is reported, with a note that the file exceeded its recorded count.

  • A baselined violation is fixed

    The entry is now stale. onStale decides whether that is ignored, warned about, or an error. Pruning writes the lower count back.

  • A file is renamed or moved

    Its entry follows the file when exactly one baselined path and one new path share a filename. Ambiguous cases are not guessed at — those violations are reported as new.

  • A file is deleted

    Its entry is dropped on the next prune.

  • A run scans a subset

    Only the files and rules covered by the run are considered. Running with --rule or against part of the tree leaves every other entry untouched rather than treating it as fixed.

Keeping it shrinking

Fixing baselined code surfaces on the next run:

01❯ 2 baselined violations have been fixed - run 'ngcompass baseline prune' to tighten the baseline
02❯ No new violations found · PASS · 4 hidden by baseline
bash
01npx ngcompass baseline prune

Pruning writes the lower counts back, so fixed violations cannot silently return under an old allowance.

Commands

  • baseline create

    Runs a full uncached analysis and records what it finds. Fails if a baseline already exists, unless --force is passed.

  • baseline show

    Prints what the baseline currently hides, grouped by rule and ranked by count. Reads the file only — no analysis runs.

  • baseline prune

    Re-counts what this run scanned, follows renamed files, and drops entries for files that no longer exist. This is what shrinks a baseline.

  • baseline update

    Re-counts what this run scanned and writes those counts, keeping entries for files it did not scan. Unlike prune, it will raise counts — use it when you are deliberately accepting new debt.

Flags accepted by the subcommands:

  • --path <path>

    Baseline file to read or write. Defaults to baseline.path from config.

  • -p, --profile <name>

    Run under a named profile, so the baseline covers the rules CI enforces.

  • --rule <id>create, update

    Record or refresh one rule, leaving other entries untouched.

  • --forcecreate

    Overwrite an existing baseline file.

  • --top <n>show

    Files listed under each rule. Default 3.

  • --skip-type-check

    Skip type-aware rules while recording. The baseline then covers only the rules that ran.

Configuration

ngcompass.config.ts
01export default defineConfig({
02 extends: 'ngcompass:recommended',
03
04 baseline: {
05 enabled: true,
06 path: '.ngcompass/baseline.json',
07 onStale: 'warn', // 'ignore' | 'warn' | 'error'
08 },
09});
  • enabledbooleandefault false

    Apply the baseline on every analyze run. Leave it false and pass --baseline when you only want it in CI.

  • pathstringdefault .ngcompass/baseline.json

    Baseline file location, relative to the project root. Override per run with --baseline <path>.

  • onStale"ignore" | "warn" | "error"default "warn"

    What to do when the baseline records more violations than the run found — meaning debt was fixed and the file is now looser than reality. error makes that a failing build.

ngcompass config health reports baseline-file-missing when the baseline is enabled but absent, and flags a large maxWarnings budget sitting alongside an active baseline — the baseline already absorbs existing warnings, so a wide budget on top only hides regressions.

In CI

.github/workflows/ngcompass.yml
01- name: Install dependencies
02 run: npm ci
03
04- name: Run ngcompass
05 run: npx ngcompass analyze --baseline --profile ci

The baseline is applied after analysis, as a filter on results. It is not part of any cache key, so toggling it does not invalidate the incremental cache, and filtered results are never written back to it.

Because the file is sorted and count-only, a pull request that grows the baseline shows up as raised numbers in the diff. Reviewing that is what keeps it from becoming a dumping ground.

Related