Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 11x 11x 11x 11x 2x 3x 3x 3x 3x 3x 13x 13x 12x 13x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 13x 9x 9x 9x 9x 9x 9x 1x 1x 1x 9x 8x 8x 9x 9x 13x 3x 3x 3x 3x 2x 3x 3x 3x 2x 2x 2x 3x 3x 3x 3x 3x 2x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 2x 2x 2x 2x 2x 2x 1x 1x | import * as fs from 'fs';
import * as path from 'path';
import type { CustomRule, Severity } from '../types';
interface RuleYamlItem {
id: string;
severity: string;
description: string;
message: string;
languages?: string[];
excludeLanguages?: string[];
}
function stripQuotes(raw: string): string {
const m = raw.match(/^(['"])(.*)\1$/);
return m ? m[2] : raw;
}
function parseYamlSimple(content: string): object[] {
const items: Array<Record<string, unknown>> = [];
let current: Record<string, unknown> | null = null;
for (const line of content.split('\n')) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) { continue; }
if (trimmed.startsWith('- ')) {
if (current) { items.push(current); }
current = {};
const indentMatch = trimmed.match(/^- (\w[\w-]*)\s*:\s*(.*)$/);
if (indentMatch) {
const key = indentMatch[1];
const raw = indentMatch[2].trim();
if (raw.startsWith('[') && raw.endsWith(']')) {
current[key] = raw.slice(1, -1).split(',').map(s =>
s.trim().replace(/^['"]|['"]$/g, '')
);
} else {
current[key] = stripQuotes(raw);
}
}
} else if (current) {
const propMatch = trimmed.match(/^(\w[\w-]*)\s*:\s*(.*)$/);
if (propMatch) {
const key = propMatch[1];
const raw = propMatch[2].trim();
if (!raw || raw === '[]') {
current[key] = [];
} else if (raw.startsWith('[') && raw.endsWith(']')) {
current[key] = raw.slice(1, -1).split(',').map(s =>
s.trim().replace(/^['"]|['"]$/g, '')
);
} else {
current[key] = stripQuotes(raw);
}
}
}
}
if (current) { items.push(current); }
return items;
}
export function loadActiveRules(workspaceRoot: string): CustomRule[] {
const rulesDir = path.join(workspaceRoot, '.code-review', 'rules');
if (!fs.existsSync(rulesDir)) { return []; }
const allRules: CustomRule[] = [];
const files = fs.readdirSync(rulesDir).filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
for (const file of files) {
const content = fs.readFileSync(path.join(rulesDir, file), 'utf-8');
const items = parseYamlSimple(content) as RuleYamlItem[];
for (const item of items) {
if (!item.id || !item.severity || !item.description || !item.message) { continue; }
const severity = (['error', 'warning', 'info'].includes(item.severity)
? (item.severity as Severity)
: 'warning');
allRules.push({
id: item.id,
severity,
description: item.description,
message: item.message,
languages: item.languages,
excludeLanguages: item.excludeLanguages,
});
}
}
return allRules;
}
export function listRuleFiles(workspaceRoot: string): string[] {
const rulesDir = path.join(workspaceRoot, '.code-review', 'rules');
if (!fs.existsSync(rulesDir)) { return []; }
return fs.readdirSync(rulesDir).filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
}
|