@aicqtools/guardrail 1.0.0-alpha.6 → 1.0.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/matcher/yaml-rule.d.ts +5 -2
- package/dist/matcher/yaml-rule.d.ts.map +1 -1
- package/dist/matcher/yaml-rule.js +7 -5
- package/dist/matcher/yaml-rule.js.map +1 -1
- package/dist/rules-default/no-direct-anthropic.yaml +6 -0
- package/dist/rules-default/no-direct-openai.yaml +8 -0
- package/dist/rules-default/no-magic-number.d.ts.map +1 -1
- package/dist/rules-default/no-magic-number.js +112 -9
- package/dist/rules-default/no-magic-number.js.map +1 -1
- package/dist/rules-default/no-process-env-leak.d.ts.map +1 -1
- package/dist/rules-default/no-process-env-leak.js +5 -2
- package/dist/rules-default/no-process-env-leak.js.map +1 -1
- package/dist/runner/apply-rule-config.d.ts +49 -0
- package/dist/runner/apply-rule-config.d.ts.map +1 -0
- package/dist/runner/apply-rule-config.js +121 -0
- package/dist/runner/apply-rule-config.js.map +1 -0
- package/dist/runner/index.d.ts +3 -1
- package/dist/runner/index.d.ts.map +1 -1
- package/dist/runner/index.js +2 -1
- package/dist/runner/index.js.map +1 -1
- package/dist/runner/run-file.d.ts.map +1 -1
- package/dist/runner/run-file.js +13 -1
- package/dist/runner/run-file.js.map +1 -1
- package/dist/runner/run-project.d.ts +19 -1
- package/dist/runner/run-project.d.ts.map +1 -1
- package/dist/runner/run-project.js +54 -5
- package/dist/runner/run-project.js.map +1 -1
- package/dist/runner/run-rule.d.ts.map +1 -1
- package/dist/runner/run-rule.js +17 -0
- package/dist/runner/run-rule.js.map +1 -1
- package/dist/runner/suppressions.d.ts +37 -0
- package/dist/runner/suppressions.d.ts.map +1 -0
- package/dist/runner/suppressions.js +127 -0
- package/dist/runner/suppressions.js.map +1 -0
- package/dist/suggest/analyze.d.ts.map +1 -1
- package/dist/suggest/analyze.js +27 -3
- package/dist/suggest/analyze.js.map +1 -1
- package/dist/suggest/format.d.ts +8 -2
- package/dist/suggest/format.d.ts.map +1 -1
- package/dist/suggest/format.js +40 -22
- package/dist/suggest/format.js.map +1 -1
- package/dist/suggest/mine.d.ts.map +1 -1
- package/dist/suggest/mine.js +21 -1
- package/dist/suggest/mine.js.map +1 -1
- package/dist/suggest/types.d.ts +12 -0
- package/dist/suggest/types.d.ts.map +1 -1
- package/package.json +5 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-project.d.ts","sourceRoot":"","sources":["../../src/runner/run-project.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-project.d.ts","sourceRoot":"","sources":["../../src/runner/run-project.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAc,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAwB,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAKhD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;CAC9C;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CA6D9E;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,gBAAgB,EAAE,OAAO,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBnB"}
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
import fastGlob from 'fast-glob';
|
|
2
|
-
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
3
4
|
import { FileCache, hashRulesetSignature } from '@aicqtools/core';
|
|
5
|
+
import { applyOverridesForFile } from './apply-rule-config.js';
|
|
4
6
|
import { runFile } from './run-file.js';
|
|
5
7
|
import { rulesetSignature } from './ruleset-signature.js';
|
|
6
8
|
export async function runProject(opts) {
|
|
7
9
|
const start = Date.now();
|
|
10
|
+
const ignore = await resolveIgnores(opts.cwd, opts.exclude, opts.respectGitignore ?? false);
|
|
8
11
|
const files = await fastGlob([...opts.include], {
|
|
9
12
|
cwd: opts.cwd,
|
|
10
|
-
ignore
|
|
13
|
+
ignore,
|
|
11
14
|
absolute: true,
|
|
12
15
|
onlyFiles: true,
|
|
13
16
|
dot: false,
|
|
14
17
|
});
|
|
15
18
|
const cache = opts.cache;
|
|
16
|
-
const
|
|
19
|
+
const overrides = opts.overrides ?? [];
|
|
20
|
+
// The ruleset hash mixes in the overrides shape so cache entries invalidate when a user adds,
|
|
21
|
+
// removes, or edits override paths/rules. Without this, a stale entry could survive a config
|
|
22
|
+
// change that should have flipped a diagnostic on or off.
|
|
23
|
+
const rulesHash = cache
|
|
24
|
+
? hashRulesetSignature([
|
|
25
|
+
...rulesetSignature(opts.rules),
|
|
26
|
+
'overrides=' + JSON.stringify(overrides),
|
|
27
|
+
])
|
|
28
|
+
: '';
|
|
17
29
|
const diagnostics = [];
|
|
18
30
|
for (const file of files) {
|
|
19
31
|
try {
|
|
32
|
+
const fileRules = applyOverridesForFile(opts.rules, overrides, file);
|
|
20
33
|
if (cache) {
|
|
21
34
|
const st = await stat(file);
|
|
22
35
|
const cached = cache.get({
|
|
@@ -29,12 +42,12 @@ export async function runProject(opts) {
|
|
|
29
42
|
diagnostics.push(...cached);
|
|
30
43
|
continue;
|
|
31
44
|
}
|
|
32
|
-
const result = await runFile(file,
|
|
45
|
+
const result = await runFile(file, fileRules);
|
|
33
46
|
cache.set({ filePath: file, mtime: Math.floor(st.mtimeMs), size: st.size, rulesHash }, result.diagnostics);
|
|
34
47
|
diagnostics.push(...result.diagnostics);
|
|
35
48
|
}
|
|
36
49
|
else {
|
|
37
|
-
const result = await runFile(file,
|
|
50
|
+
const result = await runFile(file, fileRules);
|
|
38
51
|
diagnostics.push(...result.diagnostics);
|
|
39
52
|
}
|
|
40
53
|
}
|
|
@@ -50,6 +63,42 @@ export async function runProject(opts) {
|
|
|
50
63
|
durationMs: Date.now() - start,
|
|
51
64
|
};
|
|
52
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Build the final ignore list for `fast-glob`. Always starts from the configured `exclude`;
|
|
68
|
+
* when `respectGitignore` is true, parses the root `.gitignore` (best-effort) and appends its
|
|
69
|
+
* entries. Negation (`!pattern`) and trailing-slash directory entries are honored.
|
|
70
|
+
*/
|
|
71
|
+
export async function resolveIgnores(cwd, exclude, respectGitignore) {
|
|
72
|
+
const ignores = [...exclude];
|
|
73
|
+
if (!respectGitignore)
|
|
74
|
+
return ignores;
|
|
75
|
+
try {
|
|
76
|
+
const gitignorePath = resolve(cwd, '.gitignore');
|
|
77
|
+
const st = await stat(gitignorePath);
|
|
78
|
+
if (!st.isFile())
|
|
79
|
+
return ignores;
|
|
80
|
+
const text = await readFile(gitignorePath, 'utf-8');
|
|
81
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
82
|
+
const line = raw.trim();
|
|
83
|
+
if (line.length === 0 || line.startsWith('#'))
|
|
84
|
+
continue;
|
|
85
|
+
// We intentionally don't try to fully emulate gitignore semantics — just translate the
|
|
86
|
+
// common shapes into fast-glob globs. Anything we can't reason about we leave as-is.
|
|
87
|
+
const negated = line.startsWith('!');
|
|
88
|
+
const body = (negated ? line.slice(1) : line).trim();
|
|
89
|
+
if (body.length === 0)
|
|
90
|
+
continue;
|
|
91
|
+
// Directory entry like `out/` → `**/out/**`
|
|
92
|
+
const cleaned = body.replace(/\/$/, '');
|
|
93
|
+
const glob = cleaned.includes('/') ? cleaned : `**/${cleaned}/**`;
|
|
94
|
+
ignores.push(negated ? `!${glob}` : glob);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// `.gitignore` missing / unreadable / not a regular file — fall through with static excludes.
|
|
99
|
+
}
|
|
100
|
+
return ignores;
|
|
101
|
+
}
|
|
53
102
|
function parseFailedDiagnostic(file, err) {
|
|
54
103
|
const message = err instanceof Error ? err.message : String(err);
|
|
55
104
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-project.js","sourceRoot":"","sources":["../../src/runner/run-project.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"run-project.js","sourceRoot":"","sources":["../../src/runner/run-project.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-rule.d.ts","sourceRoot":"","sources":["../../src/runner/run-rule.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"run-rule.d.ts","sourceRoot":"","sources":["../../src/runner/run-rule.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAGjC,OAAO,KAAK,EAAE,IAAI,EAA6B,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAyChE,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,CAK5E"}
|
package/dist/runner/run-rule.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Parser from 'tree-sitter';
|
|
2
|
+
import micromatch from 'micromatch';
|
|
2
3
|
import { traverse } from '../matcher/traverse.js';
|
|
3
4
|
import { makeRuleContext } from './context.js';
|
|
4
5
|
import { loadLanguage } from '@aicqtools/core';
|
|
@@ -6,6 +7,20 @@ function ruleAppliesTo(rule, language) {
|
|
|
6
7
|
const langs = Array.isArray(rule.language) ? rule.language : [rule.language];
|
|
7
8
|
return langs.includes(language);
|
|
8
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Honor `rule.pathExclude` — a list of micromatch globs. Matching is performed against the
|
|
12
|
+
* file path as supplied (absolute by default in normal runs, fixture-relative in unit tests),
|
|
13
|
+
* and also against the path with backslashes normalized to forward slashes so authors can write
|
|
14
|
+
* `**\/llm/client.*` without worrying about Windows separators. The match is "any glob" — one
|
|
15
|
+
* match is enough to skip the rule for the file.
|
|
16
|
+
*/
|
|
17
|
+
function isPathExcluded(rule, filePath) {
|
|
18
|
+
if (!rule.pathExclude || rule.pathExclude.length === 0)
|
|
19
|
+
return false;
|
|
20
|
+
const globs = [...rule.pathExclude];
|
|
21
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
22
|
+
return micromatch.isMatch(normalized, globs, { dot: true }) || micromatch.isMatch(filePath, globs, { dot: true });
|
|
23
|
+
}
|
|
9
24
|
function runFunctionRule(rule, run, tree) {
|
|
10
25
|
const ctx = makeRuleContext(run, rule);
|
|
11
26
|
traverse(tree.rootNode, (node) => {
|
|
@@ -28,6 +43,8 @@ function runPatternRule(rule, run, tree) {
|
|
|
28
43
|
export function runRule(rule, run, tree) {
|
|
29
44
|
if (!ruleAppliesTo(rule, run.language))
|
|
30
45
|
return;
|
|
46
|
+
if (isPathExcluded(rule, run.filePath))
|
|
47
|
+
return;
|
|
31
48
|
if (rule.kind === 'function')
|
|
32
49
|
runFunctionRule(rule, run, tree);
|
|
33
50
|
else
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-rule.js","sourceRoot":"","sources":["../../src/runner/run-rule.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"run-rule.js","sourceRoot":"","sources":["../../src/runner/run-rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type Parser from 'tree-sitter';
|
|
2
|
+
import type { Diagnostic, Language } from '@aicqtools/core';
|
|
3
|
+
/**
|
|
4
|
+
* Inline suppression directives — ESLint-style comment markers that suppress diagnostics
|
|
5
|
+
* for a specific line, the next line, or the entire file. Supported syntaxes:
|
|
6
|
+
*
|
|
7
|
+
* // aicq-disable-next-line <rule-id>[, <rule-id>...]
|
|
8
|
+
* // aicq-disable-line <rule-id>[, ...]
|
|
9
|
+
* // aicq-disable-file <rule-id>[, ...]
|
|
10
|
+
*
|
|
11
|
+
* Python uses `#` instead of `//`. Block comments (`/* ...\*\/`) are also recognized.
|
|
12
|
+
* The trailing rule-id list may be omitted — a bare directive suppresses *all* rules for that
|
|
13
|
+
* scope. Multiple ids may be separated by commas, whitespace, or both. Unknown ids are silently
|
|
14
|
+
* accepted (a project may rename rules; we don't want a stale directive to crash the run).
|
|
15
|
+
*/
|
|
16
|
+
export type Scope = number | 'file';
|
|
17
|
+
export interface Suppressions {
|
|
18
|
+
/** Per-line maps: line number → set of rule ids ('*' = all). */
|
|
19
|
+
readonly byLine: Map<number, Set<string> | '*'>;
|
|
20
|
+
/** File-wide suppressions. */
|
|
21
|
+
readonly fileLevel: Set<string> | '*' | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Walk the tree's comment nodes and produce a Suppressions map. Never throws — if the grammar
|
|
25
|
+
* yields no comment nodes for a given language, the result is empty (and applySuppressions is
|
|
26
|
+
* a no-op). The `language` parameter is reserved for future per-language tweaks; today it's
|
|
27
|
+
* only used to recognize that block comments may span multiple lines.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseSuppressions(tree: Parser.Tree, source: string, language: Language): Suppressions;
|
|
30
|
+
/**
|
|
31
|
+
* Filter diagnostics through the parsed suppressions. Diagnostics whose `ruleId` is suppressed
|
|
32
|
+
* either file-wide or on its specific line are removed. `@aicq/parse-failed` (and any other
|
|
33
|
+
* synthetic diagnostic emitted by the runner) is treated like any other rule and can be
|
|
34
|
+
* suppressed by id or with a bare directive.
|
|
35
|
+
*/
|
|
36
|
+
export declare function applySuppressions(diagnostics: readonly Diagnostic[], suppressions: Suppressions): Diagnostic[];
|
|
37
|
+
//# sourceMappingURL=suppressions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suppressions.d.ts","sourceRoot":"","sources":["../../src/runner/suppressions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG5D;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC;IAChD,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;CAC9C;AAMD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,GACjB,YAAY,CA0Dd;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,YAAY,EAAE,YAAY,GACzB,UAAU,EAAE,CAed"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { traverse } from '../matcher/traverse.js';
|
|
2
|
+
const COMMENT_NODE_TYPES = new Set(['comment', 'block_comment', 'line_comment']);
|
|
3
|
+
// Capture group 1: directive verb. Group 2: optional rule-id list.
|
|
4
|
+
const DIRECTIVE_RE = /aicq-disable-(next-line|line|file)\b\s*(.*)/i;
|
|
5
|
+
/**
|
|
6
|
+
* Walk the tree's comment nodes and produce a Suppressions map. Never throws — if the grammar
|
|
7
|
+
* yields no comment nodes for a given language, the result is empty (and applySuppressions is
|
|
8
|
+
* a no-op). The `language` parameter is reserved for future per-language tweaks; today it's
|
|
9
|
+
* only used to recognize that block comments may span multiple lines.
|
|
10
|
+
*/
|
|
11
|
+
export function parseSuppressions(tree, source, language) {
|
|
12
|
+
void language; // currently uniform across supported languages
|
|
13
|
+
const byLine = new Map();
|
|
14
|
+
let fileLevel = null;
|
|
15
|
+
const mergeAtLine = (line, ids) => {
|
|
16
|
+
const existing = byLine.get(line);
|
|
17
|
+
if (existing === undefined) {
|
|
18
|
+
byLine.set(line, ids === '*' ? '*' : new Set(ids));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (existing === '*' || ids === '*') {
|
|
22
|
+
byLine.set(line, '*');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
for (const id of ids)
|
|
26
|
+
existing.add(id);
|
|
27
|
+
};
|
|
28
|
+
const mergeFile = (ids) => {
|
|
29
|
+
if (fileLevel === '*' || ids === '*') {
|
|
30
|
+
fileLevel = '*';
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (fileLevel === null) {
|
|
34
|
+
fileLevel = new Set(ids);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (const id of ids)
|
|
38
|
+
fileLevel.add(id);
|
|
39
|
+
};
|
|
40
|
+
traverse(tree.rootNode, (node) => {
|
|
41
|
+
if (!COMMENT_NODE_TYPES.has(node.type))
|
|
42
|
+
return;
|
|
43
|
+
const raw = source.slice(node.startIndex, node.endIndex);
|
|
44
|
+
// Strip comment delimiters before regex match so the body is what we scan.
|
|
45
|
+
const body = stripCommentDelimiters(raw);
|
|
46
|
+
const m = DIRECTIVE_RE.exec(body);
|
|
47
|
+
if (!m)
|
|
48
|
+
return;
|
|
49
|
+
const verb = m[1]?.toLowerCase();
|
|
50
|
+
if (!verb)
|
|
51
|
+
return;
|
|
52
|
+
const ids = parseRuleIds(m[2] ?? '');
|
|
53
|
+
if (verb === 'file') {
|
|
54
|
+
mergeFile(ids);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Lines are 1-based to match Diagnostic.range.start.line
|
|
58
|
+
const startLine = node.startPosition.row + 1;
|
|
59
|
+
const endLine = node.endPosition.row + 1;
|
|
60
|
+
if (verb === 'next-line') {
|
|
61
|
+
mergeAtLine(endLine + 1, ids);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// 'line' — for a leading standalone comment, apply to the comment's own line(s).
|
|
65
|
+
// For a trailing comment (e.g. `code; // aicq-disable-line`), the comment is on the
|
|
66
|
+
// same line as the code, so this also applies correctly.
|
|
67
|
+
for (let l = startLine; l <= endLine; l++)
|
|
68
|
+
mergeAtLine(l, ids);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return { byLine, fileLevel };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Filter diagnostics through the parsed suppressions. Diagnostics whose `ruleId` is suppressed
|
|
75
|
+
* either file-wide or on its specific line are removed. `@aicq/parse-failed` (and any other
|
|
76
|
+
* synthetic diagnostic emitted by the runner) is treated like any other rule and can be
|
|
77
|
+
* suppressed by id or with a bare directive.
|
|
78
|
+
*/
|
|
79
|
+
export function applySuppressions(diagnostics, suppressions) {
|
|
80
|
+
if (suppressions.fileLevel === '*')
|
|
81
|
+
return [];
|
|
82
|
+
const fileSet = suppressions.fileLevel instanceof Set ? suppressions.fileLevel : null;
|
|
83
|
+
const hasAnyLine = suppressions.byLine.size > 0;
|
|
84
|
+
if (!fileSet && !hasAnyLine)
|
|
85
|
+
return [...diagnostics];
|
|
86
|
+
const out = [];
|
|
87
|
+
for (const d of diagnostics) {
|
|
88
|
+
if (fileSet && fileSet.has(d.ruleId))
|
|
89
|
+
continue;
|
|
90
|
+
const lineMap = suppressions.byLine.get(d.range.start.line);
|
|
91
|
+
if (lineMap === '*')
|
|
92
|
+
continue;
|
|
93
|
+
if (lineMap && lineMap.has(d.ruleId))
|
|
94
|
+
continue;
|
|
95
|
+
out.push(d);
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
function stripCommentDelimiters(raw) {
|
|
100
|
+
// `//foo` → `foo`, `# foo` → `foo`, `/* foo */` → `foo`, `<!-- foo -->` (just in case) → `foo`
|
|
101
|
+
return raw
|
|
102
|
+
.replace(/^\s*\/\*/, '')
|
|
103
|
+
.replace(/\*\/\s*$/, '')
|
|
104
|
+
.replace(/^\s*\/\//, '')
|
|
105
|
+
.replace(/^\s*#/, '')
|
|
106
|
+
.replace(/^\s*<!--/, '')
|
|
107
|
+
.replace(/-->\s*$/, '')
|
|
108
|
+
.trim();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Split the directive tail into a set of rule ids. Empty tail → '*' (bare directive).
|
|
112
|
+
* Accepts commas, whitespace, or both as separators; ignores empty tokens; lowercases nothing
|
|
113
|
+
* (rule ids are case-sensitive). Returns `'*'` when the tail is empty.
|
|
114
|
+
*/
|
|
115
|
+
function parseRuleIds(tail) {
|
|
116
|
+
const trimmed = tail.trim();
|
|
117
|
+
if (trimmed.length === 0)
|
|
118
|
+
return '*';
|
|
119
|
+
const tokens = trimmed
|
|
120
|
+
.split(/[,\s]+/)
|
|
121
|
+
.map((s) => s.trim())
|
|
122
|
+
.filter((s) => s.length > 0);
|
|
123
|
+
if (tokens.length === 0)
|
|
124
|
+
return '*';
|
|
125
|
+
return new Set(tokens);
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=suppressions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suppressions.js","sourceRoot":"","sources":["../../src/runner/suppressions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/suggest/analyze.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,kBAAkB,EAGlB,oBAAoB,EAErB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/suggest/analyze.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,kBAAkB,EAGlB,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAiBpB;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAmFzF"}
|
package/dist/suggest/analyze.js
CHANGED
|
@@ -3,13 +3,17 @@ import { readFile } from 'node:fs/promises';
|
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import fastGlob from 'fast-glob';
|
|
5
5
|
import { detectLanguage } from '@aicqtools/core';
|
|
6
|
-
import { runProject } from '../runner/run-project.js';
|
|
6
|
+
import { resolveIgnores, runProject } from '../runner/run-project.js';
|
|
7
7
|
import { buildConfigSnippet } from './format.js';
|
|
8
8
|
const PARSE_FAILED_ID = '@aicq/parse-failed';
|
|
9
9
|
const DEFAULT_TOP = 10;
|
|
10
10
|
const DEFAULT_MIN_HITS = 1;
|
|
11
11
|
const MAX_SAMPLE_LOCATIONS = 2;
|
|
12
12
|
const MIN_DEP_NAME_LENGTH = 4;
|
|
13
|
+
/** When a rule has > NOISY_RATIO times the hits of the next-ranked rule, mark it noisy. */
|
|
14
|
+
const NOISY_RATIO = 10;
|
|
15
|
+
/** Absolute floor: any info-severity rule that fires more than this is treated as noisy regardless of gap. */
|
|
16
|
+
const NOISY_ABS_THRESHOLD = 200;
|
|
13
17
|
/**
|
|
14
18
|
* Approach A — built-in rule recommender. Scans the repo with all supplied rules,
|
|
15
19
|
* ranks them by how many violations they would flag, and emits a paste-ready
|
|
@@ -26,6 +30,7 @@ export async function analyzeRepo(opts) {
|
|
|
26
30
|
exclude: opts.exclude,
|
|
27
31
|
rules: opts.rules,
|
|
28
32
|
...(opts.cache ? { cache: opts.cache } : {}),
|
|
33
|
+
...(opts.respectGitignore ? { respectGitignore: true } : {}),
|
|
29
34
|
});
|
|
30
35
|
const byRule = new Map();
|
|
31
36
|
for (const d of result.diagnostics) {
|
|
@@ -70,10 +75,15 @@ export async function analyzeRepo(opts) {
|
|
|
70
75
|
suggestions.push(makeSuggestion(rule, 0, [], true));
|
|
71
76
|
}
|
|
72
77
|
suggestions.sort((a, b) => b.hits - a.hits || a.ruleId.localeCompare(b.ruleId));
|
|
73
|
-
|
|
78
|
+
// Mark "noisy" suggestions: those whose hit count is dramatically larger than the next
|
|
79
|
+
// rule's (gap criterion) OR any info-severity rule above the absolute threshold. This
|
|
80
|
+
// information drives both the text reporter's flag and the YAML snippet's comment-out
|
|
81
|
+
// behavior, so we compute it once here.
|
|
82
|
+
const capped = applyNoisyFlag(suggestions.slice(0, top));
|
|
83
|
+
const ignore = await resolveIgnores(opts.cwd, opts.exclude, opts.respectGitignore ?? false);
|
|
74
84
|
const files = await fastGlob([...opts.include], {
|
|
75
85
|
cwd: opts.cwd,
|
|
76
|
-
ignore
|
|
86
|
+
ignore,
|
|
77
87
|
absolute: true,
|
|
78
88
|
onlyFiles: true,
|
|
79
89
|
dot: false,
|
|
@@ -106,6 +116,20 @@ function makeSuggestion(rule, hits, samples, stackMatch) {
|
|
|
106
116
|
...(stackMatch ? { stackMatch: true } : {}),
|
|
107
117
|
};
|
|
108
118
|
}
|
|
119
|
+
function applyNoisyFlag(suggestions) {
|
|
120
|
+
const out = suggestions.map((s) => ({ ...s }));
|
|
121
|
+
for (let i = 0; i < out.length; i++) {
|
|
122
|
+
const cur = out[i];
|
|
123
|
+
if (!cur)
|
|
124
|
+
continue;
|
|
125
|
+
const next = out[i + 1];
|
|
126
|
+
const gap = cur.hits > 0 && next && next.hits > 0 && cur.hits > next.hits * NOISY_RATIO;
|
|
127
|
+
const absInfo = cur.severity === 'info' && cur.hits > NOISY_ABS_THRESHOLD;
|
|
128
|
+
if (gap || absInfo)
|
|
129
|
+
cur.noisy = true;
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
109
133
|
function bareDepName(name) {
|
|
110
134
|
return name.startsWith('@') ? (name.split('/').pop() ?? name) : name;
|
|
111
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/suggest/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,QAAQ,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/suggest/analyze.ts"],"names":[],"mappings":"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"}
|
package/dist/suggest/format.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { Locale } from '@aicqtools/core';
|
|
2
2
|
import type { RuleSuggestion, RuleSuggestionReport } from './types.js';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* A paste-ready `aicq.config.yaml` fragment that enables the suggested rules.
|
|
5
|
+
*
|
|
6
|
+
* Info-severity and `noisy`-flagged rules are emitted as **commented-out** lines with a note —
|
|
7
|
+
* pasting the snippet as-is never floods the project with low-signal diagnostics, but the
|
|
8
|
+
* reader sees that those rules exist and can uncomment them after tuning.
|
|
9
|
+
*/
|
|
4
10
|
export declare function buildConfigSnippet(suggestions: readonly RuleSuggestion[]): string;
|
|
5
11
|
export declare function formatSuggestText(report: RuleSuggestionReport, locale: Locale): string;
|
|
6
|
-
export declare function formatSuggestYaml(report: RuleSuggestionReport): string;
|
|
12
|
+
export declare function formatSuggestYaml(report: RuleSuggestionReport, locale?: Locale): string;
|
|
7
13
|
//# sourceMappingURL=format.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/suggest/format.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,KAAK,EAAoB,cAAc,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/suggest/format.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,KAAK,EAAoB,cAAc,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAIzF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,CAejF;AAcD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAgDtF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,oBAAoB,EAAE,MAAM,GAAE,MAAa,GAAG,MAAM,CAY7F"}
|
package/dist/suggest/format.js
CHANGED
|
@@ -1,21 +1,44 @@
|
|
|
1
1
|
import { stringify as stringifyYaml } from 'yaml';
|
|
2
2
|
import { t } from '@aicqtools/core';
|
|
3
|
-
const NOISY_RATIO = 10;
|
|
4
3
|
const MESSAGE_WIDTH = 64;
|
|
5
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* A paste-ready `aicq.config.yaml` fragment that enables the suggested rules.
|
|
6
|
+
*
|
|
7
|
+
* Info-severity and `noisy`-flagged rules are emitted as **commented-out** lines with a note —
|
|
8
|
+
* pasting the snippet as-is never floods the project with low-signal diagnostics, but the
|
|
9
|
+
* reader sees that those rules exist and can uncomment them after tuning.
|
|
10
|
+
*/
|
|
6
11
|
export function buildConfigSnippet(suggestions) {
|
|
7
12
|
if (suggestions.length === 0)
|
|
8
13
|
return '';
|
|
9
14
|
const lines = ['modules:', ' guardrail:', ' rules:'];
|
|
10
15
|
for (const s of suggestions) {
|
|
11
16
|
const level = s.severity === 'error' ? 'error' : 'warn';
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
const noteParts = [];
|
|
18
|
+
if (s.hits > 0)
|
|
19
|
+
noteParts.push(`${s.hits} hit${s.hits === 1 ? '' : 's'}`);
|
|
20
|
+
if (s.stackMatch)
|
|
21
|
+
noteParts.push('stack match');
|
|
22
|
+
const commentOut = s.severity === 'info' || s.noisy === true;
|
|
23
|
+
if (commentOut)
|
|
24
|
+
noteParts.push(`${s.severity} severity, likely noisy — review & tune before enabling`);
|
|
25
|
+
const note = noteParts.length > 0 ? ` # ${noteParts.join(', ')}` : '';
|
|
26
|
+
const prefix = commentOut ? '# ' : ' ';
|
|
27
|
+
lines.push(`${prefix}${s.ruleId}: ${level}${note}`);
|
|
16
28
|
}
|
|
17
29
|
return lines.join('\n');
|
|
18
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Renders a multi-line banner suitable for placing above `buildConfigSnippet`'s output.
|
|
33
|
+
* Uses YAML `#` comments so the entire result is paste-safe.
|
|
34
|
+
*/
|
|
35
|
+
function snippetBanner(locale) {
|
|
36
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
37
|
+
return t(locale, 'cli.rules.suggest.snippetBanner', { date })
|
|
38
|
+
.split('\n')
|
|
39
|
+
.map((line) => `# ${line}`)
|
|
40
|
+
.join('\n');
|
|
41
|
+
}
|
|
19
42
|
export function formatSuggestText(report, locale) {
|
|
20
43
|
const lines = [];
|
|
21
44
|
lines.push(t(locale, 'cli.rules.suggest.header', {
|
|
@@ -29,18 +52,11 @@ export function formatSuggestText(report, locale) {
|
|
|
29
52
|
}
|
|
30
53
|
else {
|
|
31
54
|
lines.push(t(locale, 'cli.rules.suggest.tableHeader'));
|
|
32
|
-
|
|
33
|
-
for (let i = 0; i < report.suggestions.length - 1; i++) {
|
|
34
|
-
const cur = report.suggestions[i]?.hits ?? 0;
|
|
35
|
-
const next = report.suggestions[i + 1]?.hits ?? 0;
|
|
36
|
-
if (cur > 0 && next > 0 && cur > next * NOISY_RATIO)
|
|
37
|
-
noisy.add(i);
|
|
38
|
-
}
|
|
39
|
-
report.suggestions.forEach((s, i) => {
|
|
55
|
+
report.suggestions.forEach((s) => {
|
|
40
56
|
const flags = [];
|
|
41
57
|
if (s.stackMatch)
|
|
42
58
|
flags.push(t(locale, 'cli.rules.suggest.stackMatchNote'));
|
|
43
|
-
if (noisy
|
|
59
|
+
if (s.noisy)
|
|
44
60
|
flags.push(t(locale, 'cli.rules.suggest.noisyNote'));
|
|
45
61
|
const flagStr = flags.length > 0 ? ` ${flags.join(' ')}` : '';
|
|
46
62
|
lines.push(` ${s.ruleId} ${s.hits} ${s.severity} ${truncate(s.message, MESSAGE_WIDTH)}${flagStr}`);
|
|
@@ -57,32 +73,34 @@ export function formatSuggestText(report, locale) {
|
|
|
57
73
|
if (report.configSnippet) {
|
|
58
74
|
lines.push('');
|
|
59
75
|
lines.push(t(locale, 'cli.rules.suggest.configHint'));
|
|
76
|
+
lines.push(snippetBanner(locale));
|
|
60
77
|
lines.push(report.configSnippet);
|
|
61
78
|
}
|
|
62
79
|
if (report.patternDrafts && report.patternDrafts.length > 0) {
|
|
63
80
|
lines.push('');
|
|
64
81
|
lines.push(t(locale, 'cli.rules.suggest.patternDraftsHeader', { count: report.patternDrafts.length }));
|
|
65
|
-
lines.push(formatPatternDraftsYaml(report.patternDrafts));
|
|
82
|
+
lines.push(formatPatternDraftsYaml(report.patternDrafts, locale));
|
|
66
83
|
}
|
|
67
84
|
return lines.join('\n');
|
|
68
85
|
}
|
|
69
|
-
export function formatSuggestYaml(report) {
|
|
86
|
+
export function formatSuggestYaml(report, locale = 'en') {
|
|
70
87
|
const parts = [];
|
|
71
88
|
if (report.configSnippet) {
|
|
72
|
-
parts.push(
|
|
89
|
+
parts.push(snippetBanner(locale));
|
|
73
90
|
parts.push(report.configSnippet);
|
|
74
91
|
}
|
|
75
92
|
if (report.patternDrafts && report.patternDrafts.length > 0) {
|
|
76
93
|
if (parts.length > 0)
|
|
77
94
|
parts.push('');
|
|
78
|
-
parts.push(
|
|
79
|
-
parts.push(formatPatternDraftsYaml(report.patternDrafts));
|
|
95
|
+
parts.push(`# ${t(locale, 'cli.rules.suggest.patternDraftsBanner')}`);
|
|
96
|
+
parts.push(formatPatternDraftsYaml(report.patternDrafts, locale));
|
|
80
97
|
}
|
|
81
98
|
return parts.length > 0 ? parts.join('\n') : '# No suggestions.';
|
|
82
99
|
}
|
|
83
|
-
function formatPatternDraftsYaml(drafts) {
|
|
100
|
+
function formatPatternDraftsYaml(drafts, locale) {
|
|
101
|
+
const expHeader = t(locale, 'cli.rules.suggest.experimentalLabel');
|
|
84
102
|
return drafts
|
|
85
|
-
.map((d, i) => `# --- draft ${i + 1}/${drafts.length}: ${d.id} (${d.meta.count}x across ${d.meta.files} file${d.meta.files === 1 ? '' : 's'}) ---\n${patternDraftToYaml(d)}`)
|
|
103
|
+
.map((d, i) => `# --- ${expHeader} draft ${i + 1}/${drafts.length}: ${d.id} (${d.meta.count}x across ${d.meta.files} file${d.meta.files === 1 ? '' : 's'}) ---\n${patternDraftToYaml(d)}`)
|
|
86
104
|
.join('---\n');
|
|
87
105
|
}
|
|
88
106
|
function patternDraftToYaml(draft) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/suggest/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AAElD,OAAO,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAGpC,MAAM,
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/suggest/format.ts"],"names":[],"mappings":"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"}
|