/** * @fileoverview defineRegexListCheck - Template helper for regex-list scanners. * * Wraps {@link defineCheck} for the common "for line; for pattern; emit one * violation per match" shape that ~13 sites in @opensip-cli/checks-universal * (and a handful in @opensip-cli/checks-typescript) reimplement, often with * subtly different `lastIndex`-reset, comment-skip, and test-file-skip * semantics. * * Adopters declare patterns with {@link RegexListCheckPattern} tuples; this * helper handles iteration, regex state reset, optional comment/test-file * skipping, and per-pattern slug tagging in the violation `type` field. * * The shape mirrors the existing `no-console-log.ts` reference: each pattern * has its own `id` (UUID) and `slug`. The pattern's `slug` is emitted on * each violation as `type: pattern.slug`, matching the established * convention used by `heavy-import-detection` (`type: 'HEAVY_IMPORT' | ...`). * The `id` is purely descriptive metadata for the pattern author and is * not added to violation output. * * @example * ```typescript * export const noConsoleLog = defineRegexListCheck({ * id: '86403377-5903-478a-bdf2-e4f2f17df39f', * slug: 'no-console-log', * description: 'Disallow console.log in production code', * tags: ['logging', 'quality'], * scope: { languages: ['typescript'], concerns: ['backend'] }, * fileTypes: ['ts'], * contentFilter: 'strip-strings', * options: { skipCommentLines: true }, * patterns: [ * { * id: '38b2df63-54c3-4ab9-8a4d-5050384fa56b', * slug: 'console-log', * regex: /console\.log\s{0,10}\(/g, * message: 'console.log detected', * suggestion: 'Use a structured logger', * }, * // ... more patterns * ], * }) * ``` */ import type { CheckScope } from './check-config.js'; import type { Check } from './check-types.js'; /** * A single regex pattern entry consumed by {@link defineRegexListCheck}. * * Each entry has a stable UUID `id` and a kebab-case `slug` so the pattern * is individually addressable for documentation and developer tooling. The * `slug` is emitted on every produced violation as `type: pattern.slug`. * * @remarks Per-pattern attribution (e.g. an Aristotle SDO/SAX `provider`) * is intentionally NOT modelled here. The `provider` on * {@link DefineRegexListCheckConfig} is **check-level only** — every * pattern in a single helper invocation shares the same provider. Splitting * a pattern list into two helpers is the supported workaround when one * subset needs distinct attribution. A per-pattern field will be added * if/when a real driver appears (audit 2026-05-23 F1). */ export interface RegexListCheckPattern { /** Stable UUID identifying this pattern. Purely descriptive. */ readonly id: string; /** Kebab-case slug for this pattern (e.g. `'console-log'`). Emitted as `type` on each violation. */ readonly slug: string; /** Regex executed against each (non-skipped) line. Global flag is recommended for multi-match-per-line behaviour. */ readonly regex: RegExp; /** Violation message reported on a match. */ readonly message: string; /** Optional suggestion text for the violation. */ readonly suggestion?: string; /** * Per-pattern severity. Defaults to `'warning'`. Pattern-level severity * is preferred over a per-check default because most adopters mix * error-class and warning-class patterns inside the same regex list. */ readonly severity?: 'error' | 'warning'; } /** * Options governing line iteration in {@link defineRegexListCheck}. */ export interface RegexListCheckOptions { /** * Skip lines that {@link isCommentLine} reports as comments. * Default: `true`. */ readonly skipCommentLines?: boolean; /** * Skip files that {@link isTestFile} reports as test files. Useful for * checks that should not run against `*.test.ts` / `*.spec.ts` / * `__tests__/` paths. * Default: `false`. */ readonly skipTestFiles?: boolean; /** * Skip files under `packages/fitness/checks-*` — check-pack source often * contains literal examples of the patterns this helper detects. * Default: `false`. */ readonly skipCheckAuthoringSources?: boolean; /** * Custom file-path predicate. When provided AND it returns `true`, * the file is skipped entirely. Used by sites with site-specific * allowlists that the helper does not model (e.g. CLI-output paths * like `/commands/`, `/display/`, `/bin/`). * * The predicate runs once per file before any line iteration. */ readonly skipFile?: (filePath: string) => boolean; /** * Additional per-line skip predicate evaluated AFTER comment/test * filters but BEFORE pattern matching. Use for site-specific filters * the helper doesn't model (e.g. `no-window-alert` skips lines * starting with `import `). */ readonly skipLine?: (trimmedLine: string, rawLine: string) => boolean; /** * When `true`, after a violation is emitted on a line, skip remaining * patterns for that line — at most one violation per line in total. * Use for sites that historically emit one violation per line across * all patterns (e.g. `no-window-alert`, `no-eval`). * * Note this short-circuits at the line level, NOT the pattern level: * within a single pattern's match loop (relevant only for global * regexes), multiple matches are still emitted before the next line * starts. Combine with non-global regexes for true "one per line". * * Default: `false` (each matching pattern emits its own violation). */ readonly oneViolationPerLine?: boolean; } /** * Configuration accepted by {@link defineRegexListCheck}. * * The fields above `patterns` mirror {@link defineCheck}'s analyze-mode * `BaseCheckConfig`. The `analyze` function is synthesised by this helper. */ export interface DefineRegexListCheckConfig { readonly id: string; readonly slug: string; readonly description: string; readonly longDescription?: string; readonly tags: readonly string[]; readonly scope?: CheckScope; readonly fileTypes?: readonly string[]; readonly contentFilter?: 'raw' | 'strip-strings' | 'strip-strings-and-comments'; readonly confidence?: 'high' | 'medium' | 'low'; readonly disabled?: boolean; readonly timeout?: number; readonly docs?: string; /** * Aristotle SDO/SAX provider attribution applied to every pattern in * this check. **Check-level only** — there is no per-pattern override. * If two pattern subsets need distinct attribution, define them as two * separate checks (audit 2026-05-23 F1). */ readonly provider?: string; /** The list of regex patterns to scan each line against. */ readonly patterns: readonly RegexListCheckPattern[]; /** Line- and file-level skip toggles. */ readonly options?: RegexListCheckOptions; } /** Factory for the common "scan each line against a regex list" check pattern. */ export declare function defineRegexListCheck(config: DefineRegexListCheckConfig): Check; //# sourceMappingURL=define-regex-list-check.d.ts.map