@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,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getChangedFiles = getChangedFiles;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_util_1 = require("node:util");
|
|
6
|
+
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
7
|
+
/** Get files and changed lines from git diff. */
|
|
8
|
+
async function getChangedFiles(ref) {
|
|
9
|
+
const diffOutput = await runGitDiff(ref);
|
|
10
|
+
return parseDiffOutput(diffOutput);
|
|
11
|
+
}
|
|
12
|
+
/** Run git diff and return the raw output. */
|
|
13
|
+
async function runGitDiff(ref) {
|
|
14
|
+
const args = ['diff', '--unified=0'];
|
|
15
|
+
if (ref === undefined || ref === '') {
|
|
16
|
+
args.push('--cached');
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
args.push(ref);
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const { stdout } = await execFileAsync('git', args, {
|
|
23
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
24
|
+
});
|
|
25
|
+
return stdout;
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
29
|
+
throw new Error(`Failed to run git diff: ${msg}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Parse unified diff output into ChangedFile entries. */
|
|
33
|
+
function parseDiffOutput(output) {
|
|
34
|
+
const files = [];
|
|
35
|
+
let currentFile = null;
|
|
36
|
+
for (const line of output.split('\n')) {
|
|
37
|
+
if (line.startsWith('+++ b/')) {
|
|
38
|
+
currentFile = { filePath: line.slice(6), changedLines: new Set() };
|
|
39
|
+
files.push(currentFile);
|
|
40
|
+
}
|
|
41
|
+
else if (line.startsWith('@@ ') && currentFile) {
|
|
42
|
+
parseHunkHeader(line, currentFile.changedLines);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return files;
|
|
46
|
+
}
|
|
47
|
+
/** Parse a hunk header to extract changed line ranges. */
|
|
48
|
+
function parseHunkHeader(line, changedLines) {
|
|
49
|
+
const match = line.match(/@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/);
|
|
50
|
+
if (!match)
|
|
51
|
+
return;
|
|
52
|
+
const start = parseInt(match[1], 10);
|
|
53
|
+
const count = match[2] ? parseInt(match[2], 10) : 1;
|
|
54
|
+
for (let i = start; i < start + count; i++) {
|
|
55
|
+
changedLines.add(i);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=git-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-diff.js","sourceRoot":"","sources":["../../src/scanner/git-diff.ts"],"names":[],"mappings":";;AAYA,0CAGC;AAfD,2DAA8C;AAC9C,yCAAsC;AAEtC,MAAM,aAAa,GAAG,IAAA,qBAAS,EAAC,6BAAQ,CAAC,CAAC;AAQ1C,iDAAiD;AAC1C,KAAK,UAAU,eAAe,CAAC,GAAY;IAChD,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IACzC,OAAO,eAAe,CAAC,UAAU,CAAC,CAAC;AACrC,CAAC;AAED,8CAA8C;AAC9C,KAAK,UAAU,UAAU,CAAC,GAAY;IACpC,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACrC,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE;YAClD,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;SAC5B,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,EAAE,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,SAAS,eAAe,CAAC,MAAc;IACrC,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,IAAI,WAAW,GAAuB,IAAI,CAAC;IAE3C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,WAAW,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;YACnE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1B,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC;YACjD,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,0DAA0D;AAC1D,SAAS,eAAe,CAAC,IAAY,EAAE,YAAyB;IAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACnE,IAAI,CAAC,KAAK;QAAE,OAAO;IAEnB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EAIX,MAAM,aAAa,CAAC;AAUrB,8CAA8C;AAC9C,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAepE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scan = scan;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const index_js_1 = require("../parsers/index.js");
|
|
7
|
+
const discovery_js_1 = require("./discovery.js");
|
|
8
|
+
const git_diff_js_1 = require("./git-diff.js");
|
|
9
|
+
const index_js_2 = require("../rules/index.js");
|
|
10
|
+
const ERROR_WEIGHT = 5;
|
|
11
|
+
const WARN_WEIGHT = 2;
|
|
12
|
+
const INFO_WEIGHT = 0.5;
|
|
13
|
+
/** Run a full scan with the given options. */
|
|
14
|
+
async function scan(options) {
|
|
15
|
+
const start = Date.now();
|
|
16
|
+
const filePaths = await resolveFilePaths(options);
|
|
17
|
+
const rules = (0, index_js_2.getAllRules)();
|
|
18
|
+
const ignoreSet = new Set(options.ignore ?? []);
|
|
19
|
+
const activeRules = rules.filter((r) => !ignoreSet.has(r.id));
|
|
20
|
+
const minSeverity = options.severity ?? 'info';
|
|
21
|
+
const files = [];
|
|
22
|
+
for (const filePath of filePaths) {
|
|
23
|
+
const result = await scanSingleFile(filePath, activeRules, minSeverity);
|
|
24
|
+
if (result)
|
|
25
|
+
files.push(result);
|
|
26
|
+
}
|
|
27
|
+
return buildScanResult(files, Date.now() - start);
|
|
28
|
+
}
|
|
29
|
+
/** Resolve file paths from options (direct paths or git diff). */
|
|
30
|
+
async function resolveFilePaths(options) {
|
|
31
|
+
if (options.diff !== undefined && options.diff !== false) {
|
|
32
|
+
const ref = typeof options.diff === 'string' ? options.diff : undefined;
|
|
33
|
+
const changed = await (0, git_diff_js_1.getChangedFiles)(ref);
|
|
34
|
+
return changed.map((c) => (0, node_path_1.resolve)(c.filePath));
|
|
35
|
+
}
|
|
36
|
+
return (0, discovery_js_1.discoverFiles)(options.paths, options.ignore);
|
|
37
|
+
}
|
|
38
|
+
/** Scan a single file against all active rules. */
|
|
39
|
+
async function scanSingleFile(filePath, rules, minSeverity) {
|
|
40
|
+
const language = (0, index_js_1.getLanguage)(filePath);
|
|
41
|
+
if (!language)
|
|
42
|
+
return null;
|
|
43
|
+
let source;
|
|
44
|
+
try {
|
|
45
|
+
source = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const parserResult = (0, index_js_1.parseFile)(source, filePath);
|
|
51
|
+
const applicableRules = rules.filter((r) => r.languages.includes(language));
|
|
52
|
+
const allFindings = [];
|
|
53
|
+
for (const rule of applicableRules) {
|
|
54
|
+
const findings = rule.check(parserResult, filePath);
|
|
55
|
+
allFindings.push(...findings);
|
|
56
|
+
}
|
|
57
|
+
const filtered = filterBySeverity(allFindings, minSeverity);
|
|
58
|
+
const score = computeConfidence(filtered, parserResult.lineCount);
|
|
59
|
+
return {
|
|
60
|
+
filePath,
|
|
61
|
+
language,
|
|
62
|
+
findings: filtered,
|
|
63
|
+
confidenceScore: score,
|
|
64
|
+
lineCount: parserResult.lineCount,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** Filter findings by minimum severity level. */
|
|
68
|
+
function filterBySeverity(findings, minSeverity) {
|
|
69
|
+
const levels = { error: 2, warning: 1, info: 0 };
|
|
70
|
+
const minLevel = levels[minSeverity];
|
|
71
|
+
return findings.filter((f) => levels[f.severity] >= minLevel);
|
|
72
|
+
}
|
|
73
|
+
/** Compute a confidence score for a file based on findings. */
|
|
74
|
+
function computeConfidence(findings, lineCount) {
|
|
75
|
+
if (lineCount === 0)
|
|
76
|
+
return 100;
|
|
77
|
+
const errors = findings.filter((f) => f.severity === 'error').length;
|
|
78
|
+
const warnings = findings.filter((f) => f.severity === 'warning').length;
|
|
79
|
+
const infos = findings.filter((f) => f.severity === 'info').length;
|
|
80
|
+
const weighted = ERROR_WEIGHT * errors + WARN_WEIGHT * warnings + INFO_WEIGHT * infos;
|
|
81
|
+
return Math.max(0, Math.round(100 - (weighted / lineCount) * 100));
|
|
82
|
+
}
|
|
83
|
+
/** Build the aggregate ScanResult from individual file results. */
|
|
84
|
+
function buildScanResult(files, duration) {
|
|
85
|
+
let totalFindings = 0;
|
|
86
|
+
let errorCount = 0;
|
|
87
|
+
let warningCount = 0;
|
|
88
|
+
let infoCount = 0;
|
|
89
|
+
for (const file of files) {
|
|
90
|
+
totalFindings += file.findings.length;
|
|
91
|
+
for (const f of file.findings) {
|
|
92
|
+
if (f.severity === 'error')
|
|
93
|
+
errorCount++;
|
|
94
|
+
else if (f.severity === 'warning')
|
|
95
|
+
warningCount++;
|
|
96
|
+
else
|
|
97
|
+
infoCount++;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
files,
|
|
102
|
+
totalFindings,
|
|
103
|
+
errorCount,
|
|
104
|
+
warningCount,
|
|
105
|
+
infoCount,
|
|
106
|
+
scannedFiles: files.length,
|
|
107
|
+
duration,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/** Severity level for a finding. */
|
|
2
|
+
export type Severity = 'error' | 'warning' | 'info';
|
|
3
|
+
/** Categories of rules that detect LLM hallucination patterns. */
|
|
4
|
+
export type RuleCategory = 'phantom-imports' | 'hallucinated-apis' | 'placeholder-code' | 'confidence-patterns' | 'security-antipatterns' | 'type-safety' | 'error-handling';
|
|
5
|
+
/** Supported source languages. */
|
|
6
|
+
export type Language = 'javascript' | 'typescript' | 'python';
|
|
7
|
+
/** A suggested fix for a finding. */
|
|
8
|
+
export interface FixSuggestion {
|
|
9
|
+
description: string;
|
|
10
|
+
replacement?: string;
|
|
11
|
+
line: number;
|
|
12
|
+
column?: number;
|
|
13
|
+
endLine?: number;
|
|
14
|
+
endColumn?: number;
|
|
15
|
+
}
|
|
16
|
+
/** A single issue detected by a rule. */
|
|
17
|
+
export interface Finding {
|
|
18
|
+
ruleId: string;
|
|
19
|
+
category: RuleCategory;
|
|
20
|
+
severity: Severity;
|
|
21
|
+
message: string;
|
|
22
|
+
filePath: string;
|
|
23
|
+
line: number;
|
|
24
|
+
column: number;
|
|
25
|
+
endLine?: number;
|
|
26
|
+
endColumn?: number;
|
|
27
|
+
snippet: string;
|
|
28
|
+
explanation: string;
|
|
29
|
+
fix?: FixSuggestion;
|
|
30
|
+
}
|
|
31
|
+
/** Results for a single scanned file. */
|
|
32
|
+
export interface FileResult {
|
|
33
|
+
filePath: string;
|
|
34
|
+
language: Language;
|
|
35
|
+
findings: Finding[];
|
|
36
|
+
confidenceScore: number;
|
|
37
|
+
lineCount: number;
|
|
38
|
+
}
|
|
39
|
+
/** Aggregate results of a full scan. */
|
|
40
|
+
export interface ScanResult {
|
|
41
|
+
files: FileResult[];
|
|
42
|
+
totalFindings: number;
|
|
43
|
+
errorCount: number;
|
|
44
|
+
warningCount: number;
|
|
45
|
+
infoCount: number;
|
|
46
|
+
scannedFiles: number;
|
|
47
|
+
duration: number;
|
|
48
|
+
}
|
|
49
|
+
/** Options passed to the scanner. */
|
|
50
|
+
export interface ScanOptions {
|
|
51
|
+
paths: string[];
|
|
52
|
+
diff?: boolean | string;
|
|
53
|
+
ci?: boolean;
|
|
54
|
+
format?: 'text' | 'json';
|
|
55
|
+
fix?: boolean;
|
|
56
|
+
severity?: Severity;
|
|
57
|
+
ignore?: string[];
|
|
58
|
+
config?: string;
|
|
59
|
+
}
|
|
60
|
+
/** A parsed import statement. */
|
|
61
|
+
export interface ParsedImport {
|
|
62
|
+
source: string;
|
|
63
|
+
line: number;
|
|
64
|
+
column: number;
|
|
65
|
+
isRelative: boolean;
|
|
66
|
+
specifiers: string[];
|
|
67
|
+
}
|
|
68
|
+
/** A parsed function/method call. */
|
|
69
|
+
export interface FunctionCall {
|
|
70
|
+
object?: string;
|
|
71
|
+
method: string;
|
|
72
|
+
line: number;
|
|
73
|
+
column: number;
|
|
74
|
+
args: number;
|
|
75
|
+
}
|
|
76
|
+
/** A parsed function declaration. */
|
|
77
|
+
export interface FunctionDecl {
|
|
78
|
+
name: string;
|
|
79
|
+
line: number;
|
|
80
|
+
endLine: number;
|
|
81
|
+
params: string[];
|
|
82
|
+
hasReturnType: boolean;
|
|
83
|
+
bodyLineCount: number;
|
|
84
|
+
isEmpty: boolean;
|
|
85
|
+
returnsNullish: boolean;
|
|
86
|
+
}
|
|
87
|
+
/** A parsed comment. */
|
|
88
|
+
export interface Comment {
|
|
89
|
+
text: string;
|
|
90
|
+
line: number;
|
|
91
|
+
column: number;
|
|
92
|
+
}
|
|
93
|
+
/** A parsed type annotation. */
|
|
94
|
+
export interface TypeAnnotation {
|
|
95
|
+
text: string;
|
|
96
|
+
line: number;
|
|
97
|
+
column: number;
|
|
98
|
+
isAny: boolean;
|
|
99
|
+
}
|
|
100
|
+
/** A parsed catch block. */
|
|
101
|
+
export interface CatchBlock {
|
|
102
|
+
line: number;
|
|
103
|
+
endLine: number;
|
|
104
|
+
paramName?: string;
|
|
105
|
+
bodyLineCount: number;
|
|
106
|
+
isEmpty: boolean;
|
|
107
|
+
onlyLogs: boolean;
|
|
108
|
+
}
|
|
109
|
+
/** A parsed string literal. */
|
|
110
|
+
export interface StringLiteral {
|
|
111
|
+
value: string;
|
|
112
|
+
line: number;
|
|
113
|
+
column: number;
|
|
114
|
+
quoteStyle: 'single' | 'double' | 'backtick';
|
|
115
|
+
}
|
|
116
|
+
/** Full result from parsing a source file. */
|
|
117
|
+
export interface ParserResult {
|
|
118
|
+
language: Language;
|
|
119
|
+
imports: ParsedImport[];
|
|
120
|
+
functionCalls: FunctionCall[];
|
|
121
|
+
functionDecls: FunctionDecl[];
|
|
122
|
+
comments: Comment[];
|
|
123
|
+
typeAnnotations: TypeAnnotation[];
|
|
124
|
+
catchBlocks: CatchBlock[];
|
|
125
|
+
stringLiterals: StringLiteral[];
|
|
126
|
+
lines: string[];
|
|
127
|
+
lineCount: number;
|
|
128
|
+
}
|
|
129
|
+
/** A rule that checks parsed code for issues. */
|
|
130
|
+
export interface Rule {
|
|
131
|
+
id: string;
|
|
132
|
+
category: RuleCategory;
|
|
133
|
+
severity: Severity;
|
|
134
|
+
languages: Language[];
|
|
135
|
+
description: string;
|
|
136
|
+
check(parserResult: ParserResult, filePath: string): Finding[];
|
|
137
|
+
}
|
|
138
|
+
/** Context passed to rule checks. */
|
|
139
|
+
export interface RuleContext {
|
|
140
|
+
parserResult: ParserResult;
|
|
141
|
+
filePath: string;
|
|
142
|
+
sourceText: string;
|
|
143
|
+
}
|
|
144
|
+
/** Configuration for aireview. */
|
|
145
|
+
export interface AireviewConfig {
|
|
146
|
+
rules?: Record<string, 'off' | 'warn' | 'error'>;
|
|
147
|
+
ignore?: string[];
|
|
148
|
+
languages?: Language[];
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@avinashchby/aireview",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Catch what your AI missed -- static analysis for LLM-generated code",
|
|
5
|
+
"author": "Avinash Chaubey",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/avinashchaubey/aireview.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/avinashchaubey/aireview#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/avinashchaubey/aireview/issues"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
16
|
+
"bin": {
|
|
17
|
+
"aireview": "./bin/aireview.js"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"lint": "tsc --noEmit",
|
|
24
|
+
"prepublishOnly": "npm run build && npm test"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"linting",
|
|
28
|
+
"static-analysis",
|
|
29
|
+
"ai",
|
|
30
|
+
"llm",
|
|
31
|
+
"code-review",
|
|
32
|
+
"hallucination-detection",
|
|
33
|
+
"eslint",
|
|
34
|
+
"code-quality"
|
|
35
|
+
],
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18.0.0"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"bin",
|
|
43
|
+
"LICENSE",
|
|
44
|
+
"README.md"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"chalk": "^5.4.1",
|
|
48
|
+
"commander": "^12.1.0",
|
|
49
|
+
"fast-glob": "^3.3.3",
|
|
50
|
+
"ignore": "^7.0.3"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^22.13.14",
|
|
54
|
+
"typescript": "^5.7.3",
|
|
55
|
+
"vitest": "^3.0.9"
|
|
56
|
+
}
|
|
57
|
+
}
|