/** * @fileoverview Keyword-agnostic inline-suppression primitive (ADR-0014). * * The shared machinery behind `@fitness-ignore-*` and `@graph-ignore-*`: a * pure text scan of comment directives plus a `Signal`-stream filter. It is * keyword-agnostic (the directive keywords are a parameter) and performs no * file I/O — content is read through an injected reader, keeping the kernel * pure. The *vocabulary* (which keyword a tool uses) stays tool-owned and * explicit; only the *machinery* is shared. * * Matching unit: each signal is tested against a set of **candidate source * locations** (default: the signal's own `code`). Graph supplies extra * candidate locations for `graph:cycle` (the SCC members) so a directive above * any member matches — without this module knowing what an SCC is. * * Suppression is **unconditional**: a directive with no `-- reason` still * suppresses. Reason quality is audited out-of-band (e.g. the * `graph-ignore-hygiene` / `fitness-ignore-hygiene` checks), never enforced * here. */ import type { Signal } from '../types/signal.js'; /** The two directive keywords a tool owns. */ export interface SuppressionKeywords { /** File-level directive, e.g. `@fitness-ignore-file` / `@graph-ignore-file`. */ readonly file: string; /** Next-line directive, e.g. `@fitness-ignore-next-line` / `@graph-ignore-next-line`. */ readonly nextLine: string; } /** A candidate source location a directive may target for a given signal. */ export interface SuppressionLocation { readonly file: string; /** 1-based line; omit for a file-only candidate. */ readonly line?: number; } /** Request for {@link filterSignalsBySuppressions}. */ export interface SuppressionRequest { readonly signals: readonly Signal[]; /** The tool's explicit directive keywords. */ readonly keywords: SuppressionKeywords; /** Injected content reader (kernel performs no file I/O). */ readonly readFile: (filePath: string) => Promise; /** * Candidate locations a directive may target for this signal. Defaults to * the signal's own `code` location. Graph overrides this for `graph:cycle`. */ readonly locate?: (signal: Signal) => readonly SuppressionLocation[]; /** * The id a directive must name to suppress this signal. Defaults to * `signal.ruleId`. Fitness passes `() => checkId` to reproduce its exact * per-check semantics. */ readonly ruleIdOf?: (signal: Signal) => string; } /** One suppressed signal + the directive that suppressed it. */ export interface SuppressionMatch { readonly signal: Signal; readonly ruleId: string; readonly file: string; /** The 1-based line, or `'file'` for a file-level directive. */ readonly line: number | 'file'; } /** Result of {@link filterSignalsBySuppressions}. */ export interface SuppressionResult { readonly kept: readonly Signal[]; readonly suppressed: readonly SuppressionMatch[]; } /** * Per-file scan result. Exposed so lower-level callers (e.g. fitness's * `parseFileIgnoreDirective` / `parseIgnoreDirectives` wrappers) can build on * the same single scan implementation instead of re-deriving it. */ export interface SuppressionScan { /** Ids named by a file-level directive. */ readonly fileIgnoredIds: ReadonlySet; /** Target 1-based line → ids named by a next-line directive. */ readonly lineIgnoredIds: ReadonlyMap>; /** 1-based lines that ARE directive comments (anti-recursion guard). */ readonly directiveLines: ReadonlySet; } /** Scan a file's content once, extracting every directive for `keywords`. */ export declare function scanSuppressionDirectives(content: string, keywords: SuppressionKeywords): SuppressionScan; /** * Filter a `Signal` stream by inline suppression directives. * * Each file referenced by a candidate location is read once (via the injected * `readFile`) and scanned once. A signal is suppressed when, for ANY of its * candidate locations, the directive id (`ruleIdOf(signal)`, default * `signal.ruleId`) is file-ignored for that file, or next-line-ignored at that * location's line. A location pointing AT a directive line is never suppressed * by a next-line directive (anti-recursion); file-level still applies. * * Read-failure posture (fail-loud; Phase 5): the injected `readFile` reads * project SOURCE files the analyzers already loaded, so a read failure is * UNEXPECTED. An `ENOENT` (the file was genuinely removed) is non-fatal but * ATTRIBUTED — it is surfaced via a warning-level `signals.suppress.directive- * file-missing` log (so a potentially-dropped waiver is diagnosable) and that * file contributes no directives. ANY other read failure (`EACCES`, `EMFILE`, * decode error, …) is propagated (THROWS) — the run aborts loudly rather than * silently dropping a waiver and leaking the waived signal as a finding. */ export declare function filterSignalsBySuppressions(request: SuppressionRequest): Promise; //# sourceMappingURL=suppress.d.ts.map