@avinashchby/aireview 0.1.0
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/LICENSE +21 -0
- package/README.md +157 -0
- package/bin/aireview.js +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +79 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +78 -0
- package/dist/config.js.map +1 -0
- package/dist/fixer/index.d.ts +4 -0
- package/dist/fixer/index.d.ts.map +1 -0
- package/dist/fixer/index.js +54 -0
- package/dist/fixer/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/index.d.ts +8 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +47 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/python-parser.d.ts +4 -0
- package/dist/parsers/python-parser.d.ts.map +1 -0
- package/dist/parsers/python-parser.js +235 -0
- package/dist/parsers/python-parser.js.map +1 -0
- package/dist/parsers/typescript-parser.d.ts +4 -0
- package/dist/parsers/typescript-parser.d.ts.map +1 -0
- package/dist/parsers/typescript-parser.js +300 -0
- package/dist/parsers/typescript-parser.js.map +1 -0
- package/dist/reporters/ci-reporter.d.ts +4 -0
- package/dist/reporters/ci-reporter.d.ts.map +1 -0
- package/dist/reporters/ci-reporter.js +49 -0
- package/dist/reporters/ci-reporter.js.map +1 -0
- package/dist/reporters/index.d.ts +6 -0
- package/dist/reporters/index.d.ts.map +1 -0
- package/dist/reporters/index.js +15 -0
- package/dist/reporters/index.js.map +1 -0
- package/dist/reporters/json-reporter.d.ts +4 -0
- package/dist/reporters/json-reporter.d.ts.map +1 -0
- package/dist/reporters/json-reporter.js +8 -0
- package/dist/reporters/json-reporter.js.map +1 -0
- package/dist/reporters/text-reporter.d.ts +4 -0
- package/dist/reporters/text-reporter.d.ts.map +1 -0
- package/dist/reporters/text-reporter.js +110 -0
- package/dist/reporters/text-reporter.js.map +1 -0
- package/dist/rules/confidence-patterns.d.ts +4 -0
- package/dist/rules/confidence-patterns.d.ts.map +1 -0
- package/dist/rules/confidence-patterns.js +186 -0
- package/dist/rules/confidence-patterns.js.map +1 -0
- package/dist/rules/engine.d.ts +19 -0
- package/dist/rules/engine.d.ts.map +1 -0
- package/dist/rules/engine.js +58 -0
- package/dist/rules/engine.js.map +1 -0
- package/dist/rules/error-handling.d.ts +4 -0
- package/dist/rules/error-handling.d.ts.map +1 -0
- package/dist/rules/error-handling.js +162 -0
- package/dist/rules/error-handling.js.map +1 -0
- package/dist/rules/hallucinated-apis.d.ts +4 -0
- package/dist/rules/hallucinated-apis.d.ts.map +1 -0
- package/dist/rules/hallucinated-apis.js +196 -0
- package/dist/rules/hallucinated-apis.js.map +1 -0
- package/dist/rules/index.d.ts +4 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +27 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/phantom-imports.d.ts +4 -0
- package/dist/rules/phantom-imports.d.ts.map +1 -0
- package/dist/rules/phantom-imports.js +300 -0
- package/dist/rules/phantom-imports.js.map +1 -0
- package/dist/rules/placeholder-code.d.ts +4 -0
- package/dist/rules/placeholder-code.d.ts.map +1 -0
- package/dist/rules/placeholder-code.js +113 -0
- package/dist/rules/placeholder-code.js.map +1 -0
- package/dist/rules/security-antipatterns.d.ts +4 -0
- package/dist/rules/security-antipatterns.d.ts.map +1 -0
- package/dist/rules/security-antipatterns.js +174 -0
- package/dist/rules/security-antipatterns.js.map +1 -0
- package/dist/rules/type-safety.d.ts +4 -0
- package/dist/rules/type-safety.d.ts.map +1 -0
- package/dist/rules/type-safety.js +148 -0
- package/dist/rules/type-safety.js.map +1 -0
- package/dist/scanner/discovery.d.ts +3 -0
- package/dist/scanner/discovery.d.ts.map +1 -0
- package/dist/scanner/discovery.js +76 -0
- package/dist/scanner/discovery.js.map +1 -0
- package/dist/scanner/git-diff.d.ts +8 -0
- package/dist/scanner/git-diff.d.ts.map +1 -0
- package/dist/scanner/git-diff.js +58 -0
- package/dist/scanner/git-diff.js.map +1 -0
- package/dist/scanner/index.d.ts +4 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +110 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/types.d.ts +150 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getReporter = getReporter;
|
|
4
|
+
const text_reporter_js_1 = require("./text-reporter.js");
|
|
5
|
+
const json_reporter_js_1 = require("./json-reporter.js");
|
|
6
|
+
const ci_reporter_js_1 = require("./ci-reporter.js");
|
|
7
|
+
/** Get the appropriate reporter based on format and CI mode. */
|
|
8
|
+
function getReporter(format = 'text', ci = false) {
|
|
9
|
+
if (ci)
|
|
10
|
+
return ci_reporter_js_1.reportCi;
|
|
11
|
+
if (format === 'json')
|
|
12
|
+
return json_reporter_js_1.reportJson;
|
|
13
|
+
return text_reporter_js_1.reportText;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reporters/index.ts"],"names":[],"mappings":";;AASA,kCAOC;AAfD,yDAAgD;AAChD,yDAAgD;AAChD,qDAA4C;AAK5C,gEAAgE;AAChE,SAAgB,WAAW,CACzB,SAA0B,MAAM,EAChC,KAAc,KAAK;IAEnB,IAAI,EAAE;QAAE,OAAO,yBAAQ,CAAC;IACxB,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,6BAAU,CAAC;IACzC,OAAO,6BAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-reporter.d.ts","sourceRoot":"","sources":["../../src/reporters/json-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,uDAAuD;AACvD,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAEnD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reportJson = reportJson;
|
|
4
|
+
/** Output scan results as formatted JSON to stdout. */
|
|
5
|
+
function reportJson(result) {
|
|
6
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=json-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-reporter.js","sourceRoot":"","sources":["../../src/reporters/json-reporter.ts"],"names":[],"mappings":";;AAGA,gCAEC;AAHD,uDAAuD;AACvD,SAAgB,UAAU,CAAC,MAAkB;IAC3C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-reporter.d.ts","sourceRoot":"","sources":["../../src/reporters/text-reporter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAiC,MAAM,aAAa,CAAC;AAE7E,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAgBnD"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.reportText = reportText;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
/** Format and print scan results as pretty terminal output. */
|
|
9
|
+
function reportText(result) {
|
|
10
|
+
if (result.totalFindings === 0) {
|
|
11
|
+
console.log(chalk_1.default.green('\n No issues found!\n'));
|
|
12
|
+
printSummary(result);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (const file of result.files) {
|
|
16
|
+
if (file.findings.length === 0)
|
|
17
|
+
continue;
|
|
18
|
+
printFileHeader(file);
|
|
19
|
+
for (const finding of file.findings) {
|
|
20
|
+
printFinding(finding);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
printSummary(result);
|
|
24
|
+
}
|
|
25
|
+
/** Print the file header with path and confidence score. */
|
|
26
|
+
function printFileHeader(file) {
|
|
27
|
+
const scoreColor = file.confidenceScore >= 80
|
|
28
|
+
? chalk_1.default.green
|
|
29
|
+
: file.confidenceScore >= 50
|
|
30
|
+
? chalk_1.default.yellow
|
|
31
|
+
: chalk_1.default.red;
|
|
32
|
+
console.log(`\n${chalk_1.default.underline(file.filePath)} ` +
|
|
33
|
+
`(confidence: ${scoreColor(`${file.confidenceScore}%`)})`);
|
|
34
|
+
}
|
|
35
|
+
/** Print a single finding with icon, location, and details. */
|
|
36
|
+
function printFinding(f) {
|
|
37
|
+
const icon = getSeverityIcon(f.severity);
|
|
38
|
+
const loc = chalk_1.default.dim(`${f.line}:${f.column}`);
|
|
39
|
+
const ruleId = chalk_1.default.dim(`[${f.ruleId}]`);
|
|
40
|
+
console.log(` ${icon} ${loc} ${f.message} ${ruleId}`);
|
|
41
|
+
printSnippet(f.snippet, f.line);
|
|
42
|
+
printExplanation(f.explanation);
|
|
43
|
+
printFix(f);
|
|
44
|
+
}
|
|
45
|
+
/** Get the severity icon string. */
|
|
46
|
+
function getSeverityIcon(severity) {
|
|
47
|
+
switch (severity) {
|
|
48
|
+
case 'error': return chalk_1.default.red('\u2717');
|
|
49
|
+
case 'warning': return chalk_1.default.yellow('\u26A0');
|
|
50
|
+
case 'info': return chalk_1.default.blue('\u2139');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Print the code snippet with the offending line. */
|
|
54
|
+
function printSnippet(snippet, _line) {
|
|
55
|
+
if (!snippet)
|
|
56
|
+
return;
|
|
57
|
+
const lines = snippet.split('\n');
|
|
58
|
+
for (const line of lines) {
|
|
59
|
+
console.log(chalk_1.default.dim(` | ${line}`));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** Print the explanation. */
|
|
63
|
+
function printExplanation(explanation) {
|
|
64
|
+
if (!explanation)
|
|
65
|
+
return;
|
|
66
|
+
console.log(chalk_1.default.cyan(` ${explanation}`));
|
|
67
|
+
}
|
|
68
|
+
/** Print the suggested fix if available. */
|
|
69
|
+
function printFix(f) {
|
|
70
|
+
if (!f.fix)
|
|
71
|
+
return;
|
|
72
|
+
console.log(chalk_1.default.green(` Fix: ${f.fix.description}`));
|
|
73
|
+
if (f.fix.replacement !== undefined) {
|
|
74
|
+
console.log(chalk_1.default.green(` Replacement: ${f.fix.replacement}`));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Print the summary section. */
|
|
78
|
+
function printSummary(result) {
|
|
79
|
+
console.log(chalk_1.default.dim('\n---'));
|
|
80
|
+
console.log(`Scanned ${chalk_1.default.bold(String(result.scannedFiles))} files in ` +
|
|
81
|
+
`${chalk_1.default.bold(String(result.duration))}ms`);
|
|
82
|
+
const parts = [];
|
|
83
|
+
if (result.errorCount > 0)
|
|
84
|
+
parts.push(chalk_1.default.red(`${result.errorCount} errors`));
|
|
85
|
+
if (result.warningCount > 0)
|
|
86
|
+
parts.push(chalk_1.default.yellow(`${result.warningCount} warnings`));
|
|
87
|
+
if (result.infoCount > 0)
|
|
88
|
+
parts.push(chalk_1.default.blue(`${result.infoCount} info`));
|
|
89
|
+
if (parts.length > 0) {
|
|
90
|
+
console.log(`Found ${parts.join(', ')}`);
|
|
91
|
+
}
|
|
92
|
+
printConfidenceScores(result);
|
|
93
|
+
console.log('');
|
|
94
|
+
}
|
|
95
|
+
/** Print per-file confidence scores. */
|
|
96
|
+
function printConfidenceScores(result) {
|
|
97
|
+
const filesWithFindings = result.files.filter((f) => f.findings.length > 0);
|
|
98
|
+
if (filesWithFindings.length === 0)
|
|
99
|
+
return;
|
|
100
|
+
console.log(chalk_1.default.dim('\nConfidence scores:'));
|
|
101
|
+
for (const file of filesWithFindings) {
|
|
102
|
+
const scoreColor = file.confidenceScore >= 80
|
|
103
|
+
? chalk_1.default.green
|
|
104
|
+
: file.confidenceScore >= 50
|
|
105
|
+
? chalk_1.default.yellow
|
|
106
|
+
: chalk_1.default.red;
|
|
107
|
+
console.log(` ${file.filePath}: ${scoreColor(`${file.confidenceScore}%`)}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=text-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-reporter.js","sourceRoot":"","sources":["../../src/reporters/text-reporter.ts"],"names":[],"mappings":";;;;;AAIA,gCAgBC;AApBD,kDAA0B;AAG1B,+DAA+D;AAC/D,SAAgB,UAAU,CAAC,MAAkB;IAC3C,IAAI,MAAM,CAAC,aAAa,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;QACnD,YAAY,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACzC,eAAe,CAAC,IAAI,CAAC,CAAC;QACtB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,YAAY,CAAC,MAAM,CAAC,CAAC;AACvB,CAAC;AAED,4DAA4D;AAC5D,SAAS,eAAe,CAAC,IAAgB;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,IAAI,EAAE;QAC3C,CAAC,CAAC,eAAK,CAAC,KAAK;QACb,CAAC,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE;YAC1B,CAAC,CAAC,eAAK,CAAC,MAAM;YACd,CAAC,CAAC,eAAK,CAAC,GAAG,CAAC;IAEhB,OAAO,CAAC,GAAG,CACT,KAAK,eAAK,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG;QACtC,gBAAgB,UAAU,CAAC,GAAG,IAAI,CAAC,eAAe,GAAG,CAAC,GAAG,CAC1D,CAAC;AACJ,CAAC;AAED,+DAA+D;AAC/D,SAAS,YAAY,CAAC,CAAU;IAC9B,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,eAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,eAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAE1C,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;IACzD,YAAY,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAChC,gBAAgB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAChC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACd,CAAC;AAED,oCAAoC;AACpC,SAAS,eAAe,CAAC,QAAkB;IACzC,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,OAAO,CAAC,CAAC,OAAO,eAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,KAAK,SAAS,CAAC,CAAC,OAAO,eAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9C,KAAK,MAAM,CAAC,CAAC,OAAO,eAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,sDAAsD;AACtD,SAAS,YAAY,CAAC,OAAe,EAAE,KAAa;IAClD,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,6BAA6B;AAC7B,SAAS,gBAAgB,CAAC,WAAmB;IAC3C,IAAI,CAAC,WAAW;QAAE,OAAO;IACzB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,OAAO,WAAW,EAAE,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,4CAA4C;AAC5C,SAAS,QAAQ,CAAC,CAAU;IAC1B,IAAI,CAAC,CAAC,CAAC,GAAG;QAAE,OAAO;IACnB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC,CAAC,GAAG,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED,iCAAiC;AACjC,SAAS,YAAY,CAAC,MAAkB;IACtC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CACT,WAAW,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,YAAY;QAC9D,GAAG,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAC3C,CAAC;IAEF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,eAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,UAAU,SAAS,CAAC,CAAC,CAAC;IAChF,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,eAAK,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,YAAY,WAAW,CAAC,CAAC,CAAC;IACzF,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,eAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC;IAE7E,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,wCAAwC;AACxC,SAAS,qBAAqB,CAAC,MAAkB;IAC/C,MAAM,iBAAiB,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5E,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAE3C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAC/C,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,IAAI,EAAE;YAC3C,CAAC,CAAC,eAAK,CAAC,KAAK;YACb,CAAC,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE;gBAC1B,CAAC,CAAC,eAAK,CAAC,MAAM;gBACd,CAAC,CAAC,eAAK,CAAC,GAAG,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,QAAQ,KAAK,UAAU,CAAC,GAAG,IAAI,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confidence-patterns.d.ts","sourceRoot":"","sources":["../../src/rules/confidence-patterns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmC,MAAM,aAAa,CAAC;AA6PpE,oCAAoC;AACpC,eAAO,MAAM,sBAAsB,EAAE,IAgBpC,CAAC"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.confidencePatternsRule = void 0;
|
|
4
|
+
/** Variable names considered overly generic. */
|
|
5
|
+
const GENERIC_NAMES = new Set([
|
|
6
|
+
'data', 'result', 'temp', 'tmp', 'item', 'thing',
|
|
7
|
+
'stuff', 'foo', 'bar', 'baz', 'test', 'value', 'obj', 'x',
|
|
8
|
+
]);
|
|
9
|
+
/** LLM hedging comment patterns. */
|
|
10
|
+
const HEDGING_PATTERNS = [
|
|
11
|
+
/this\s+should\s+work/i,
|
|
12
|
+
/you\s+may\s+need\s+to/i,
|
|
13
|
+
/adjust\s+as\s+needed/i,
|
|
14
|
+
/modify\s+as\s+necessary/i,
|
|
15
|
+
/depending\s+on\s+your/i,
|
|
16
|
+
/replace\s+with\s+your/i,
|
|
17
|
+
/example\s+implementation/i,
|
|
18
|
+
/basic\s+implementation/i,
|
|
19
|
+
/simple\s+implementation/i,
|
|
20
|
+
];
|
|
21
|
+
/** Common magic number exceptions that should not be flagged. */
|
|
22
|
+
const ALLOWED_NUMBERS = new Set([
|
|
23
|
+
0, 1, 2, 10, 100, 1000, 0.5, -1,
|
|
24
|
+
]);
|
|
25
|
+
/** Create a finding for confidence-patterns. */
|
|
26
|
+
function makeFinding(line, column, snippet, message, explanation, severity, filePath) {
|
|
27
|
+
return {
|
|
28
|
+
ruleId: 'confidence-patterns',
|
|
29
|
+
category: 'confidence-patterns',
|
|
30
|
+
severity,
|
|
31
|
+
message,
|
|
32
|
+
filePath,
|
|
33
|
+
line,
|
|
34
|
+
column,
|
|
35
|
+
snippet,
|
|
36
|
+
explanation,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Check for functions where ALL parameter names are generic.
|
|
41
|
+
* Skip lambdas / short functions (1-line arrow functions).
|
|
42
|
+
*/
|
|
43
|
+
function checkGenericNames(parserResult, filePath) {
|
|
44
|
+
const findings = [];
|
|
45
|
+
for (const fn of parserResult.functionDecls) {
|
|
46
|
+
if (fn.params.length === 0)
|
|
47
|
+
continue;
|
|
48
|
+
// Skip short lambdas (body <= 1 line)
|
|
49
|
+
if (fn.bodyLineCount <= 1)
|
|
50
|
+
continue;
|
|
51
|
+
const allGeneric = fn.params.every((p) => GENERIC_NAMES.has(p));
|
|
52
|
+
if (allGeneric && fn.params.length > 0) {
|
|
53
|
+
findings.push(makeFinding(fn.line, 1, `function ${fn.name}(${fn.params.join(', ')})`, `All parameters in '${fn.name}' use generic names: ${fn.params.join(', ')}`, 'Use descriptive parameter names that convey purpose.', 'info', filePath));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return findings;
|
|
57
|
+
}
|
|
58
|
+
/** Check comments for LLM hedging language. */
|
|
59
|
+
function checkHedgingComments(parserResult, filePath) {
|
|
60
|
+
const findings = [];
|
|
61
|
+
for (const comment of parserResult.comments) {
|
|
62
|
+
for (const pattern of HEDGING_PATTERNS) {
|
|
63
|
+
if (pattern.test(comment.text)) {
|
|
64
|
+
findings.push(makeFinding(comment.line, comment.column, comment.text, `Hedging comment: "${extractMatch(comment.text, pattern)}"`, 'LLM-generated code often includes hedging language. Review and verify the implementation.', 'warning', filePath));
|
|
65
|
+
break; // One finding per comment
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return findings;
|
|
70
|
+
}
|
|
71
|
+
/** Extract the matched portion of text. */
|
|
72
|
+
function extractMatch(text, pattern) {
|
|
73
|
+
const match = pattern.exec(text);
|
|
74
|
+
return match ? match[0] : text.slice(0, 40);
|
|
75
|
+
}
|
|
76
|
+
/** Check for inconsistent quote styles in string literals. */
|
|
77
|
+
function checkQuoteConsistency(parserResult, filePath) {
|
|
78
|
+
const literals = parserResult.stringLiterals;
|
|
79
|
+
if (literals.length < 4)
|
|
80
|
+
return []; // Not enough to judge
|
|
81
|
+
let singles = 0;
|
|
82
|
+
let doubles = 0;
|
|
83
|
+
for (const lit of literals) {
|
|
84
|
+
if (lit.quoteStyle === 'single')
|
|
85
|
+
singles++;
|
|
86
|
+
else if (lit.quoteStyle === 'double')
|
|
87
|
+
doubles++;
|
|
88
|
+
// backticks excluded from consistency check
|
|
89
|
+
}
|
|
90
|
+
const total = singles + doubles;
|
|
91
|
+
if (total === 0)
|
|
92
|
+
return [];
|
|
93
|
+
const singlePct = singles / total;
|
|
94
|
+
const doublePct = doubles / total;
|
|
95
|
+
// Flag if neither dominates > 70%
|
|
96
|
+
if (singlePct <= 0.7 && doublePct <= 0.7 && total >= 4) {
|
|
97
|
+
return [makeFinding(1, 1, `${singles} single-quoted, ${doubles} double-quoted`, `Inconsistent quote style: ${singles} single vs ${doubles} double quotes`, 'Mixed quote styles may indicate code from multiple sources. Standardize on one style.', 'info', filePath)];
|
|
98
|
+
}
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
/** Check for 3+ identical catch block bodies. */
|
|
102
|
+
function checkIdenticalCatchBlocks(parserResult, filePath) {
|
|
103
|
+
const catchBodies = new Map();
|
|
104
|
+
for (const cb of parserResult.catchBlocks) {
|
|
105
|
+
const bodyKey = extractCatchBody(parserResult.lines, cb.line, cb.endLine);
|
|
106
|
+
if (!bodyKey)
|
|
107
|
+
continue;
|
|
108
|
+
const lines = catchBodies.get(bodyKey) ?? [];
|
|
109
|
+
lines.push(cb.line);
|
|
110
|
+
catchBodies.set(bodyKey, lines);
|
|
111
|
+
}
|
|
112
|
+
const findings = [];
|
|
113
|
+
for (const [body, lines] of catchBodies) {
|
|
114
|
+
if (lines.length >= 3) {
|
|
115
|
+
findings.push(makeFinding(lines[0], 1, body.slice(0, 80), `${lines.length} identical catch blocks found (lines: ${lines.join(', ')})`, 'Identical catch blocks suggest copy-pasted error handling. Consider a shared error handler.', 'warning', filePath));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return findings;
|
|
119
|
+
}
|
|
120
|
+
/** Extract the body text of a catch block from source lines. */
|
|
121
|
+
function extractCatchBody(lines, startLine, endLine) {
|
|
122
|
+
const bodyLines = [];
|
|
123
|
+
for (let i = startLine; i <= Math.min(endLine, lines.length); i++) {
|
|
124
|
+
const line = lines[i - 1];
|
|
125
|
+
if (line !== undefined)
|
|
126
|
+
bodyLines.push(line.trim());
|
|
127
|
+
}
|
|
128
|
+
return bodyLines.join('\n');
|
|
129
|
+
}
|
|
130
|
+
/** Check for magic numbers in source lines. */
|
|
131
|
+
function checkMagicNumbers(parserResult, filePath) {
|
|
132
|
+
const findings = [];
|
|
133
|
+
const magicPattern = /(?<!\w)(-?\d+\.?\d*(?:e[+-]?\d+)?)(?!\w)/gi;
|
|
134
|
+
for (let i = 0; i < parserResult.lines.length; i++) {
|
|
135
|
+
const line = parserResult.lines[i];
|
|
136
|
+
const trimmed = line.trim();
|
|
137
|
+
const lineNum = i + 1;
|
|
138
|
+
// Skip comments, imports, and common declarations
|
|
139
|
+
if (isSkippableLine(trimmed))
|
|
140
|
+
continue;
|
|
141
|
+
checkLineForMagicNumbers(trimmed, lineNum, magicPattern, filePath, findings);
|
|
142
|
+
}
|
|
143
|
+
return findings;
|
|
144
|
+
}
|
|
145
|
+
/** Determine if a line should be skipped for magic number checks. */
|
|
146
|
+
function isSkippableLine(trimmed) {
|
|
147
|
+
return (trimmed.startsWith('//') ||
|
|
148
|
+
trimmed.startsWith('#') ||
|
|
149
|
+
trimmed.startsWith('*') ||
|
|
150
|
+
trimmed.startsWith('import ') ||
|
|
151
|
+
trimmed.startsWith('from ') ||
|
|
152
|
+
trimmed.startsWith('const ') && trimmed.includes('=') && !trimmed.includes('(') ||
|
|
153
|
+
/^\s*export\s/.test(trimmed) ||
|
|
154
|
+
trimmed === '');
|
|
155
|
+
}
|
|
156
|
+
/** Check a single line for magic numbers. */
|
|
157
|
+
function checkLineForMagicNumbers(trimmed, lineNum, pattern, filePath, findings) {
|
|
158
|
+
pattern.lastIndex = 0;
|
|
159
|
+
let match;
|
|
160
|
+
const seen = new Set();
|
|
161
|
+
while ((match = pattern.exec(trimmed)) !== null) {
|
|
162
|
+
const num = parseFloat(match[1]);
|
|
163
|
+
if (isNaN(num) || ALLOWED_NUMBERS.has(num) || seen.has(num))
|
|
164
|
+
continue;
|
|
165
|
+
seen.add(num);
|
|
166
|
+
findings.push(makeFinding(lineNum, match.index + 1, trimmed, `Magic number ${num} — consider extracting to a named constant`, 'Unexplained numeric literals reduce code readability.', 'info', filePath));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/** The confidence-patterns rule. */
|
|
170
|
+
exports.confidencePatternsRule = {
|
|
171
|
+
id: 'confidence-patterns',
|
|
172
|
+
category: 'confidence-patterns',
|
|
173
|
+
severity: 'info',
|
|
174
|
+
languages: ['javascript', 'typescript', 'python'],
|
|
175
|
+
description: 'Detect patterns suggesting low-confidence LLM-generated code.',
|
|
176
|
+
check(parserResult, filePath) {
|
|
177
|
+
const findings = [];
|
|
178
|
+
findings.push(...checkGenericNames(parserResult, filePath));
|
|
179
|
+
findings.push(...checkHedgingComments(parserResult, filePath));
|
|
180
|
+
findings.push(...checkQuoteConsistency(parserResult, filePath));
|
|
181
|
+
findings.push(...checkIdenticalCatchBlocks(parserResult, filePath));
|
|
182
|
+
findings.push(...checkMagicNumbers(parserResult, filePath));
|
|
183
|
+
return findings;
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
//# sourceMappingURL=confidence-patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confidence-patterns.js","sourceRoot":"","sources":["../../src/rules/confidence-patterns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Rule, Finding, ParserResult, Severity } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Run all applicable rules against parsed source and collect findings.
|
|
4
|
+
* Only runs rules whose languages array includes the file's language.
|
|
5
|
+
* Returns findings sorted by line number ascending.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runRules(rules: Rule[], parserResult: ParserResult, filePath: string): Finding[];
|
|
8
|
+
/**
|
|
9
|
+
* Filter out findings below the minimum severity threshold.
|
|
10
|
+
* Severity ordering: error > warning > info.
|
|
11
|
+
*/
|
|
12
|
+
export declare function filterBySeverity(findings: Finding[], minSeverity: Severity): Finding[];
|
|
13
|
+
/**
|
|
14
|
+
* Compute a confidence score for a file based on its findings.
|
|
15
|
+
* Score ranges from 0 (low confidence) to 100 (high confidence).
|
|
16
|
+
* Formula: max(0, round(100 - (errors*5 + warnings*2 + infos*0.5) / max(lineCount,1) * 100))
|
|
17
|
+
*/
|
|
18
|
+
export declare function computeConfidenceScore(findings: Finding[], lineCount: number): number;
|
|
19
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/rules/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AASpE;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,IAAI,EAAE,EACb,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,MAAM,GACf,OAAO,EAAE,CAYX;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,WAAW,EAAE,QAAQ,GACpB,OAAO,EAAE,CAGX;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,OAAO,EAAE,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CAcR"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runRules = runRules;
|
|
4
|
+
exports.filterBySeverity = filterBySeverity;
|
|
5
|
+
exports.computeConfidenceScore = computeConfidenceScore;
|
|
6
|
+
/** Severity weight ordering: higher index = more severe. */
|
|
7
|
+
const SEVERITY_ORDER = {
|
|
8
|
+
info: 0,
|
|
9
|
+
warning: 1,
|
|
10
|
+
error: 2,
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Run all applicable rules against parsed source and collect findings.
|
|
14
|
+
* Only runs rules whose languages array includes the file's language.
|
|
15
|
+
* Returns findings sorted by line number ascending.
|
|
16
|
+
*/
|
|
17
|
+
function runRules(rules, parserResult, filePath) {
|
|
18
|
+
const language = parserResult.language;
|
|
19
|
+
const findings = [];
|
|
20
|
+
for (const rule of rules) {
|
|
21
|
+
if (!rule.languages.includes(language))
|
|
22
|
+
continue;
|
|
23
|
+
const ruleFindings = rule.check(parserResult, filePath);
|
|
24
|
+
findings.push(...ruleFindings);
|
|
25
|
+
}
|
|
26
|
+
findings.sort((a, b) => a.line - b.line);
|
|
27
|
+
return findings;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Filter out findings below the minimum severity threshold.
|
|
31
|
+
* Severity ordering: error > warning > info.
|
|
32
|
+
*/
|
|
33
|
+
function filterBySeverity(findings, minSeverity) {
|
|
34
|
+
const minLevel = SEVERITY_ORDER[minSeverity];
|
|
35
|
+
return findings.filter((f) => SEVERITY_ORDER[f.severity] >= minLevel);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Compute a confidence score for a file based on its findings.
|
|
39
|
+
* Score ranges from 0 (low confidence) to 100 (high confidence).
|
|
40
|
+
* Formula: max(0, round(100 - (errors*5 + warnings*2 + infos*0.5) / max(lineCount,1) * 100))
|
|
41
|
+
*/
|
|
42
|
+
function computeConfidenceScore(findings, lineCount) {
|
|
43
|
+
let errors = 0;
|
|
44
|
+
let warnings = 0;
|
|
45
|
+
let infos = 0;
|
|
46
|
+
for (const f of findings) {
|
|
47
|
+
if (f.severity === 'error')
|
|
48
|
+
errors++;
|
|
49
|
+
else if (f.severity === 'warning')
|
|
50
|
+
warnings++;
|
|
51
|
+
else
|
|
52
|
+
infos++;
|
|
53
|
+
}
|
|
54
|
+
const penalty = errors * 5 + warnings * 2 + infos * 0.5;
|
|
55
|
+
const denominator = Math.max(lineCount, 1);
|
|
56
|
+
return Math.max(0, Math.round(100 - (penalty / denominator) * 100));
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/rules/engine.ts"],"names":[],"mappings":";;AAcA,4BAgBC;AAMD,4CAMC;AAOD,wDAiBC;AAhED,4DAA4D;AAC5D,MAAM,cAAc,GAA6B;IAC/C,IAAI,EAAE,CAAC;IACP,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,CAAC;CACT,CAAC;AAEF;;;;GAIG;AACH,SAAgB,QAAQ,CACtB,KAAa,EACb,YAA0B,EAC1B,QAAgB;IAEhB,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC;IACvC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,SAAS;QACjD,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QACxD,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IACjC,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAC9B,QAAmB,EACnB,WAAqB;IAErB,MAAM,QAAQ,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC7C,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACH,SAAgB,sBAAsB,CACpC,QAAmB,EACnB,SAAiB;IAEjB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO;YAAE,MAAM,EAAE,CAAC;aAChC,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;YAAE,QAAQ,EAAE,CAAC;;YACzC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC;IACxD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,OAAO,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handling.d.ts","sourceRoot":"","sources":["../../src/rules/error-handling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAyB,MAAM,aAAa,CAAC;AAyN1D,oEAAoE;AACpE,eAAO,MAAM,iBAAiB,EAAE,IAO/B,CAAC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.errorHandlingRule = void 0;
|
|
4
|
+
const RULE_ID = 'error-handling';
|
|
5
|
+
const CATEGORY = 'error-handling';
|
|
6
|
+
/** Build a finding with standard fields pre-filled. */
|
|
7
|
+
function makeFinding(filePath, line, snippet, severity, message, explanation) {
|
|
8
|
+
return {
|
|
9
|
+
ruleId: RULE_ID,
|
|
10
|
+
category: CATEGORY,
|
|
11
|
+
severity,
|
|
12
|
+
message,
|
|
13
|
+
filePath,
|
|
14
|
+
line,
|
|
15
|
+
column: 0,
|
|
16
|
+
snippet,
|
|
17
|
+
explanation,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Detect empty catch blocks and catch-only-logs from AST data. */
|
|
21
|
+
function detectCatchBlockIssues(pr, filePath) {
|
|
22
|
+
const findings = [];
|
|
23
|
+
for (const cb of pr.catchBlocks) {
|
|
24
|
+
const snippet = pr.lines[cb.line - 1] ?? '';
|
|
25
|
+
if (cb.isEmpty) {
|
|
26
|
+
findings.push(makeFinding(filePath, cb.line, snippet, 'error', 'Empty catch block silently swallows errors', 'Empty catch blocks hide failures, making bugs impossible to diagnose. ' +
|
|
27
|
+
'At minimum, log the error. Ideally, re-throw, return an error result, or handle specifically.'));
|
|
28
|
+
}
|
|
29
|
+
else if (cb.onlyLogs) {
|
|
30
|
+
findings.push(makeFinding(filePath, cb.line, snippet, 'warning', 'Catch block only logs the error without handling it', 'Logging alone does not recover from the error. The caller may assume success. ' +
|
|
31
|
+
'Re-throw the error, return a failure result, or implement specific recovery logic.'));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return findings;
|
|
35
|
+
}
|
|
36
|
+
/** Detect bare except: in Python (no exception type specified). */
|
|
37
|
+
function detectBareExcept(pr, filePath) {
|
|
38
|
+
if (pr.language !== 'python')
|
|
39
|
+
return [];
|
|
40
|
+
const findings = [];
|
|
41
|
+
for (let i = 0; i < pr.lines.length; i++) {
|
|
42
|
+
const line = pr.lines[i];
|
|
43
|
+
if (/^\s*except\s*:/.test(line)) {
|
|
44
|
+
findings.push(makeFinding(filePath, i + 1, line, 'warning', 'Bare `except:` catches all exceptions including SystemExit and KeyboardInterrupt', 'Use `except Exception:` to catch only standard errors, or catch specific ' +
|
|
45
|
+
'exception types for targeted error handling.'));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return findings;
|
|
49
|
+
}
|
|
50
|
+
/** Detect swallowed promise rejections: .catch(() => {}) or .catch(() => null). */
|
|
51
|
+
function detectSwallowedPromises(pr, filePath) {
|
|
52
|
+
if (pr.language === 'python')
|
|
53
|
+
return [];
|
|
54
|
+
const findings = [];
|
|
55
|
+
for (let i = 0; i < pr.lines.length; i++) {
|
|
56
|
+
const line = pr.lines[i];
|
|
57
|
+
if (/\.catch\(\s*\(\s*\)\s*=>\s*\{\s*\}\s*\)/.test(line) ||
|
|
58
|
+
/\.catch\(\s*\(\s*\w*\s*\)\s*=>\s*\{\s*\}\s*\)/.test(line) ||
|
|
59
|
+
/\.catch\(\s*\(\s*\)\s*=>\s*null\s*\)/.test(line)) {
|
|
60
|
+
findings.push(makeFinding(filePath, i + 1, line, 'error', 'Promise rejection is silently swallowed', 'Empty .catch() handlers hide async errors. Handle the error, re-throw it, ' +
|
|
61
|
+
'or use a logging handler that also propagates the failure.'));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return findings;
|
|
65
|
+
}
|
|
66
|
+
/** Detect catch blocks that return null/undefined (error swallowing). */
|
|
67
|
+
function detectCatchReturnNull(pr, filePath) {
|
|
68
|
+
if (pr.language === 'python')
|
|
69
|
+
return [];
|
|
70
|
+
const findings = [];
|
|
71
|
+
for (let i = 0; i < pr.lines.length; i++) {
|
|
72
|
+
const line = pr.lines[i];
|
|
73
|
+
if (/catch\s*\(\s*\w+\s*\)\s*\{\s*return\s+(null|undefined)\s*;?\s*\}/.test(line)) {
|
|
74
|
+
findings.push(makeFinding(filePath, i + 1, line, 'warning', 'Catch block swallows error by returning null/undefined', 'Returning null from a catch block hides the error from the caller. Return a ' +
|
|
75
|
+
'Result/Either type, throw a domain error, or use a sentinel that callers can check.'));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return findings;
|
|
79
|
+
}
|
|
80
|
+
/** Detect .then() without a corresponding .catch(). */
|
|
81
|
+
function detectMissingCatch(pr, filePath) {
|
|
82
|
+
if (pr.language === 'python')
|
|
83
|
+
return [];
|
|
84
|
+
const findings = [];
|
|
85
|
+
for (let i = 0; i < pr.lines.length; i++) {
|
|
86
|
+
const line = pr.lines[i];
|
|
87
|
+
if (/\.then\s*\(/.test(line) && !/\.catch\s*\(/.test(line)) {
|
|
88
|
+
const nextLine = pr.lines[i + 1] ?? '';
|
|
89
|
+
if (!/\.catch\s*\(/.test(nextLine)) {
|
|
90
|
+
findings.push(makeFinding(filePath, i + 1, line, 'info', 'Promise chain may be missing .catch() handler', 'Unhandled promise rejections crash Node.js and cause silent failures in browsers. ' +
|
|
91
|
+
'Add .catch() or use async/await with try/catch. Note: this may be a false positive ' +
|
|
92
|
+
'if the promise is awaited or handled elsewhere.'));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return findings;
|
|
97
|
+
}
|
|
98
|
+
/** Detect process.exit() without a preceding error log. */
|
|
99
|
+
function detectProcessExit(pr, filePath) {
|
|
100
|
+
if (pr.language === 'python')
|
|
101
|
+
return [];
|
|
102
|
+
const findings = [];
|
|
103
|
+
for (let i = 0; i < pr.lines.length; i++) {
|
|
104
|
+
if (/process\.exit\s*\(\s*[01]\s*\)/.test(pr.lines[i])) {
|
|
105
|
+
const prevLine = i > 0 ? pr.lines[i - 1] : '';
|
|
106
|
+
const hasLog = /console\.(error|warn|log)|logger\.(error|warn)/.test(prevLine);
|
|
107
|
+
if (!hasLog) {
|
|
108
|
+
findings.push(makeFinding(filePath, i + 1, pr.lines[i], 'info', 'process.exit() called without a preceding error log', 'Calling process.exit() without logging makes it hard to diagnose why the process ' +
|
|
109
|
+
'terminated. Log an error message before exiting, or throw an error and let the ' +
|
|
110
|
+
'top-level handler manage shutdown.'));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return findings;
|
|
115
|
+
}
|
|
116
|
+
/** Max lines for a reasonable try block. */
|
|
117
|
+
const MAX_TRY_LINES = 50;
|
|
118
|
+
/** Detect overly large try blocks by estimating from catch positions. */
|
|
119
|
+
function detectLargeTryBlocks(pr, filePath) {
|
|
120
|
+
const findings = [];
|
|
121
|
+
for (const cb of pr.catchBlocks) {
|
|
122
|
+
const catchLine = cb.line;
|
|
123
|
+
let tryLine = -1;
|
|
124
|
+
for (let i = catchLine - 2; i >= 0; i--) {
|
|
125
|
+
if (/\btry\s*\{/.test(pr.lines[i]) || /^\s*try\s*:/.test(pr.lines[i])) {
|
|
126
|
+
tryLine = i + 1;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (tryLine > 0) {
|
|
131
|
+
const blockSize = catchLine - tryLine;
|
|
132
|
+
if (blockSize > MAX_TRY_LINES) {
|
|
133
|
+
findings.push(makeFinding(filePath, tryLine, pr.lines[tryLine - 1] ?? '', 'info', `Try block is ${blockSize} lines long (>${MAX_TRY_LINES})`, 'Large try blocks make it unclear which operation might fail and catch ' +
|
|
134
|
+
'unrelated errors. Extract smaller operations and wrap only the specific ' +
|
|
135
|
+
'call that can throw.'));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return findings;
|
|
140
|
+
}
|
|
141
|
+
/** Main check: runs all sub-detectors and merges results. */
|
|
142
|
+
function check(parserResult, filePath) {
|
|
143
|
+
return [
|
|
144
|
+
...detectCatchBlockIssues(parserResult, filePath),
|
|
145
|
+
...detectBareExcept(parserResult, filePath),
|
|
146
|
+
...detectSwallowedPromises(parserResult, filePath),
|
|
147
|
+
...detectCatchReturnNull(parserResult, filePath),
|
|
148
|
+
...detectMissingCatch(parserResult, filePath),
|
|
149
|
+
...detectProcessExit(parserResult, filePath),
|
|
150
|
+
...detectLargeTryBlocks(parserResult, filePath),
|
|
151
|
+
];
|
|
152
|
+
}
|
|
153
|
+
/** Rule detecting error handling anti-patterns across languages. */
|
|
154
|
+
exports.errorHandlingRule = {
|
|
155
|
+
id: RULE_ID,
|
|
156
|
+
category: CATEGORY,
|
|
157
|
+
severity: 'error',
|
|
158
|
+
languages: ['javascript', 'typescript', 'python'],
|
|
159
|
+
description: 'Detects error handling anti-patterns including empty catches, swallowed errors, and missing handlers',
|
|
160
|
+
check,
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=error-handling.js.map
|