@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Avinash Chaubey
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# aireview
|
|
2
|
+
|
|
3
|
+
**Catch what your AI missed.** Static analysis for LLM-generated code -- no API keys, no cloud, no cost.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/aireview)
|
|
6
|
+
[](https://github.com/avinashchaubey/aireview/blob/main/LICENSE)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx aireview .
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
src/api.ts (confidence: 42%)
|
|
15
|
+
✗ 3:1 'openai-functions' is a commonly hallucinated package [phantom-imports]
|
|
16
|
+
| import { createFunction } from 'openai-functions';
|
|
17
|
+
|
|
18
|
+
✗ 14:5 'fs.readFileAsync' does not exist [hallucinated-apis]
|
|
19
|
+
| const data = await fs.readFileAsync('config.json');
|
|
20
|
+
Fix: Use 'fs.promises.readFile'
|
|
21
|
+
|
|
22
|
+
✗ 22:0 eval() is a code injection vector [security-antipatterns]
|
|
23
|
+
| const result = eval(userInput);
|
|
24
|
+
|
|
25
|
+
⚠ 28:1 Hedging comment: "adjust as needed" [confidence-patterns]
|
|
26
|
+
| // adjust as needed for your use case
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
Scanned 12 files in 38ms
|
|
30
|
+
Found 3 errors, 1 warning
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Why this exists
|
|
34
|
+
|
|
35
|
+
LLMs write confident-looking code that compiles, passes a glance review, and breaks in production. The failure modes are predictable:
|
|
36
|
+
|
|
37
|
+
- **Phantom imports** -- packages that sound right but don't exist on npm/PyPI
|
|
38
|
+
- **Hallucinated APIs** -- `fs.readFileAsync()`, `array.flatten()`, `dict.has_key()` -- methods that were never real or were removed years ago
|
|
39
|
+
- **Placeholder stubs** -- empty function bodies, `// TODO` comments, `throw new Error("Not implemented")` hidden behind working-looking signatures
|
|
40
|
+
- **Security holes** -- `eval()`, SQL string concatenation, hardcoded API keys -- patterns LLMs reproduce from training data without understanding the risk
|
|
41
|
+
- **Swallowed errors** -- `catch(e) {}`, bare `except:`, `.catch(() => {})` -- silent failure modes that make debugging impossible
|
|
42
|
+
|
|
43
|
+
These patterns are hard to catch in code review because they look intentional. `aireview` knows the specific shapes of LLM mistakes and flags them before they ship.
|
|
44
|
+
|
|
45
|
+
**Zero API calls.** Pure AST parsing and pattern matching. Runs in milliseconds, works offline, costs nothing.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx aireview . # run without installing
|
|
51
|
+
npm install -g aireview # or install globally
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Requires Node.js >= 18.
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
aireview . # scan current directory
|
|
60
|
+
aireview src/api.ts # scan a specific file
|
|
61
|
+
aireview src/ lib/ # scan multiple paths
|
|
62
|
+
aireview --diff # scan staged git changes
|
|
63
|
+
aireview --diff HEAD~1 # scan last commit
|
|
64
|
+
aireview --ci # CI mode: exit 1 if errors found
|
|
65
|
+
aireview --format json # JSON output for tooling
|
|
66
|
+
aireview --fix # auto-fix safe issues
|
|
67
|
+
aireview --severity error # only errors, skip warnings/info
|
|
68
|
+
aireview --ignore phantom-imports # skip specific rules
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Detection rules
|
|
72
|
+
|
|
73
|
+
| Rule | Catches | Severity |
|
|
74
|
+
|------|---------|----------|
|
|
75
|
+
| `phantom-imports` | Imports of packages not in your dependency file, known hallucinated package names | warning/error |
|
|
76
|
+
| `hallucinated-apis` | `fs.readFileAsync()`, `array.flatten()`, `new Buffer()`, `dict.has_key()`, 30+ more | error |
|
|
77
|
+
| `placeholder-code` | TODO/FIXME, empty functions, `NotImplementedError`, `// ...` elisions | warning/error |
|
|
78
|
+
| `confidence-patterns` | Generic variable names (`data`, `result`, `temp`), hedging comments, inconsistent style | info/warning |
|
|
79
|
+
| `security-antipatterns` | `eval()`, `new Function()`, SQL injection, hardcoded secrets, disabled TLS | error |
|
|
80
|
+
| `type-safety` | `any` overuse, `as any` casts, `@ts-ignore`, `@ts-nocheck`, loose equality | warning/error |
|
|
81
|
+
| `error-handling` | Empty catch blocks, catch-only-logs, bare `except:`, missing `.catch()` | error/warning |
|
|
82
|
+
|
|
83
|
+
## Configuration
|
|
84
|
+
|
|
85
|
+
Create `.aireviewrc.json` in your project root:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"rules": {
|
|
90
|
+
"phantom-imports": "error",
|
|
91
|
+
"hallucinated-apis": "error",
|
|
92
|
+
"placeholder-code": "warn",
|
|
93
|
+
"confidence-patterns": "off",
|
|
94
|
+
"security-antipatterns": "error",
|
|
95
|
+
"type-safety": "warn",
|
|
96
|
+
"error-handling": "error"
|
|
97
|
+
},
|
|
98
|
+
"ignore": ["*.test.ts", "*.spec.js"]
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Or add an `"aireview"` key to your `package.json`.
|
|
103
|
+
|
|
104
|
+
## GitHub Actions
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
name: AI Code Review
|
|
108
|
+
on: [pull_request]
|
|
109
|
+
|
|
110
|
+
jobs:
|
|
111
|
+
aireview:
|
|
112
|
+
runs-on: ubuntu-latest
|
|
113
|
+
steps:
|
|
114
|
+
- uses: actions/checkout@v4
|
|
115
|
+
with:
|
|
116
|
+
fetch-depth: 0
|
|
117
|
+
|
|
118
|
+
- uses: actions/setup-node@v4
|
|
119
|
+
with:
|
|
120
|
+
node-version: '20'
|
|
121
|
+
|
|
122
|
+
- name: Run aireview
|
|
123
|
+
run: npx aireview --diff origin/main --ci
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Findings appear as inline annotations on the PR diff. Use `--format json` to pipe into other tools.
|
|
127
|
+
|
|
128
|
+
## Programmatic API
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { scan } from 'aireview';
|
|
132
|
+
|
|
133
|
+
const result = await scan({
|
|
134
|
+
paths: ['src/'],
|
|
135
|
+
severity: 'warning',
|
|
136
|
+
ignore: ['confidence-patterns'],
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
for (const file of result.files) {
|
|
140
|
+
console.log(`${file.filePath}: ${file.confidenceScore}% confidence`);
|
|
141
|
+
for (const finding of file.findings) {
|
|
142
|
+
console.log(` ${finding.line}:${finding.column} ${finding.message}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Supported languages
|
|
148
|
+
|
|
149
|
+
- JavaScript (`.js`, `.jsx`) -- TypeScript compiler API
|
|
150
|
+
- TypeScript (`.ts`, `.tsx`) -- TypeScript compiler API
|
|
151
|
+
- Python (`.py`) -- regex-based parser (no native dependencies)
|
|
152
|
+
|
|
153
|
+
Designed for extensibility. Add a language by implementing a parser that returns `ParserResult` and registering rules.
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
MIT
|
package/bin/aireview.js
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const index_js_1 = require("./scanner/index.js");
|
|
5
|
+
const index_js_2 = require("./reporters/index.js");
|
|
6
|
+
const index_js_3 = require("./fixer/index.js");
|
|
7
|
+
const config_js_1 = require("./config.js");
|
|
8
|
+
/** Create and configure the CLI program. */
|
|
9
|
+
function createProgram() {
|
|
10
|
+
const program = new commander_1.Command();
|
|
11
|
+
program
|
|
12
|
+
.name('aireview')
|
|
13
|
+
.description('Static analysis tool that detects LLM hallucination patterns in code')
|
|
14
|
+
.version('0.1.0')
|
|
15
|
+
.argument('[paths...]', 'paths to scan', ['.'])
|
|
16
|
+
.option('--diff [ref]', 'scan git diff (staged if no ref)')
|
|
17
|
+
.option('--ci', 'CI mode with GitHub Actions annotations')
|
|
18
|
+
.option('--format <format>', 'output format (text or json)', 'text')
|
|
19
|
+
.option('--fix', 'auto-fix issues where possible')
|
|
20
|
+
.option('--severity <level>', 'minimum severity to report (error, warning, info)', 'info')
|
|
21
|
+
.option('--ignore <rules>', 'comma-separated rule IDs to skip')
|
|
22
|
+
.option('--config <path>', 'path to config file')
|
|
23
|
+
.action(runScan);
|
|
24
|
+
return program;
|
|
25
|
+
}
|
|
26
|
+
/** Main scan action handler. */
|
|
27
|
+
async function runScan(paths, opts) {
|
|
28
|
+
const config = await (0, config_js_1.loadConfig)(opts.config);
|
|
29
|
+
const options = buildScanOptions(paths, opts, config);
|
|
30
|
+
const result = await (0, index_js_1.scan)(options);
|
|
31
|
+
if (opts.fix) {
|
|
32
|
+
const fixCount = await (0, index_js_3.applyFixes)(result);
|
|
33
|
+
if (fixCount > 0) {
|
|
34
|
+
console.log(`Applied ${fixCount} fixes.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const format = validateFormat(opts.format);
|
|
38
|
+
const reporter = (0, index_js_2.getReporter)(format, opts.ci ?? false);
|
|
39
|
+
reporter(result);
|
|
40
|
+
if (result.errorCount > 0 && opts.ci) {
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Build ScanOptions from CLI args and config. */
|
|
45
|
+
function buildScanOptions(paths, opts, config) {
|
|
46
|
+
const ignoreRules = opts.ignore
|
|
47
|
+
? opts.ignore.split(',').map((s) => s.trim())
|
|
48
|
+
: [];
|
|
49
|
+
return {
|
|
50
|
+
paths: paths.length > 0 ? paths : ['.'],
|
|
51
|
+
diff: opts.diff,
|
|
52
|
+
ci: opts.ci,
|
|
53
|
+
format: validateFormat(opts.format),
|
|
54
|
+
fix: opts.fix,
|
|
55
|
+
severity: validateSeverity(opts.severity),
|
|
56
|
+
ignore: [...ignoreRules, ...(config.ignore ?? [])],
|
|
57
|
+
config: opts.config,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Validate and return a format option. */
|
|
61
|
+
function validateFormat(format) {
|
|
62
|
+
if (format === 'json')
|
|
63
|
+
return 'json';
|
|
64
|
+
return 'text';
|
|
65
|
+
}
|
|
66
|
+
/** Validate and return a severity option. */
|
|
67
|
+
function validateSeverity(severity) {
|
|
68
|
+
if (severity === 'error' || severity === 'warning' || severity === 'info') {
|
|
69
|
+
return severity;
|
|
70
|
+
}
|
|
71
|
+
return 'info';
|
|
72
|
+
}
|
|
73
|
+
/** Entry point. */
|
|
74
|
+
const program = createProgram();
|
|
75
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
76
|
+
console.error('Fatal error:', err instanceof Error ? err.message : String(err));
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AASjD,yDAAyD;AACzD,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAgB7E"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadConfig = loadConfig;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const CONFIG_FILENAME = '.aireviewrc.json';
|
|
8
|
+
const DEFAULT_CONFIG = {
|
|
9
|
+
rules: {},
|
|
10
|
+
ignore: [],
|
|
11
|
+
languages: ['javascript', 'typescript', 'python'],
|
|
12
|
+
};
|
|
13
|
+
/** Load aireview configuration from file or defaults. */
|
|
14
|
+
async function loadConfig(configPath) {
|
|
15
|
+
if (configPath) {
|
|
16
|
+
return mergeWithDefaults(await readConfigFile(configPath));
|
|
17
|
+
}
|
|
18
|
+
const found = await findConfigFile(process.cwd());
|
|
19
|
+
if (found) {
|
|
20
|
+
return mergeWithDefaults(await readConfigFile(found));
|
|
21
|
+
}
|
|
22
|
+
const pkgConfig = await loadFromPackageJson(process.cwd());
|
|
23
|
+
if (pkgConfig) {
|
|
24
|
+
return mergeWithDefaults(pkgConfig);
|
|
25
|
+
}
|
|
26
|
+
return { ...DEFAULT_CONFIG };
|
|
27
|
+
}
|
|
28
|
+
/** Read and parse a config file. */
|
|
29
|
+
async function readConfigFile(path) {
|
|
30
|
+
try {
|
|
31
|
+
const content = await (0, promises_1.readFile)(path, 'utf-8');
|
|
32
|
+
return JSON.parse(content);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Walk up directories looking for .aireviewrc.json. */
|
|
39
|
+
async function findConfigFile(startDir) {
|
|
40
|
+
let dir = startDir;
|
|
41
|
+
const root = (0, node_path_1.dirname)(dir);
|
|
42
|
+
for (let i = 0; i < 20; i++) {
|
|
43
|
+
const candidate = (0, node_path_1.join)(dir, CONFIG_FILENAME);
|
|
44
|
+
if ((0, node_fs_1.existsSync)(candidate))
|
|
45
|
+
return candidate;
|
|
46
|
+
const parent = (0, node_path_1.dirname)(dir);
|
|
47
|
+
if (parent === dir || parent === root)
|
|
48
|
+
break;
|
|
49
|
+
dir = parent;
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/** Check package.json for an "aireview" config key. */
|
|
54
|
+
async function loadFromPackageJson(startDir) {
|
|
55
|
+
const pkgPath = (0, node_path_1.join)(startDir, 'package.json');
|
|
56
|
+
if (!(0, node_fs_1.existsSync)(pkgPath))
|
|
57
|
+
return null;
|
|
58
|
+
try {
|
|
59
|
+
const content = await (0, promises_1.readFile)(pkgPath, 'utf-8');
|
|
60
|
+
const pkg = JSON.parse(content);
|
|
61
|
+
if (pkg['aireview'] && typeof pkg['aireview'] === 'object') {
|
|
62
|
+
return pkg['aireview'];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Ignore parse errors
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
/** Merge a partial config with defaults. */
|
|
71
|
+
function mergeWithDefaults(partial) {
|
|
72
|
+
return {
|
|
73
|
+
rules: { ...DEFAULT_CONFIG.rules, ...partial.rules },
|
|
74
|
+
ignore: partial.ignore ?? DEFAULT_CONFIG.ignore,
|
|
75
|
+
languages: partial.languages ?? DEFAULT_CONFIG.languages,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixer/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAW,MAAM,aAAa,CAAC;AAEvD,6FAA6F;AAC7F,wBAAsB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAYpE"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyFixes = applyFixes;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
/** Apply auto-fixes for findings that have a replacement. Returns count of fixes applied. */
|
|
6
|
+
async function applyFixes(result) {
|
|
7
|
+
let totalFixed = 0;
|
|
8
|
+
for (const file of result.files) {
|
|
9
|
+
const fixable = getFixableFindings(file.findings);
|
|
10
|
+
if (fixable.length === 0)
|
|
11
|
+
continue;
|
|
12
|
+
const fixed = await applyFixesToFile(file.filePath, fixable);
|
|
13
|
+
totalFixed += fixed;
|
|
14
|
+
}
|
|
15
|
+
return totalFixed;
|
|
16
|
+
}
|
|
17
|
+
/** Get findings that have a fix with a replacement, sorted bottom-up. */
|
|
18
|
+
function getFixableFindings(findings) {
|
|
19
|
+
return findings
|
|
20
|
+
.filter((f) => f.fix?.replacement !== undefined)
|
|
21
|
+
.sort((a, b) => b.line - a.line);
|
|
22
|
+
}
|
|
23
|
+
/** Apply fixes to a single file, processing from bottom to top. */
|
|
24
|
+
async function applyFixesToFile(filePath, findings) {
|
|
25
|
+
let source;
|
|
26
|
+
try {
|
|
27
|
+
source = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
const lines = source.split('\n');
|
|
33
|
+
let applied = 0;
|
|
34
|
+
for (const finding of findings) {
|
|
35
|
+
if (!finding.fix?.replacement === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
const lineIdx = finding.line - 1;
|
|
38
|
+
if (lineIdx < 0 || lineIdx >= lines.length)
|
|
39
|
+
continue;
|
|
40
|
+
const replacement = finding.fix.replacement;
|
|
41
|
+
lines[lineIdx] = applyLineReplacement(lines[lineIdx], finding.column - 1, finding.fix.endColumn ? finding.fix.endColumn - 1 : undefined, replacement);
|
|
42
|
+
applied++;
|
|
43
|
+
}
|
|
44
|
+
if (applied > 0) {
|
|
45
|
+
await (0, promises_1.writeFile)(filePath, lines.join('\n'), 'utf-8');
|
|
46
|
+
}
|
|
47
|
+
return applied;
|
|
48
|
+
}
|
|
49
|
+
/** Apply a replacement to a specific position within a line. */
|
|
50
|
+
function applyLineReplacement(line, startCol, endCol, replacement) {
|
|
51
|
+
const end = endCol ?? line.length;
|
|
52
|
+
return line.slice(0, startCol) + replacement + line.slice(end);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fixer/index.ts"],"names":[],"mappings":";;AAIA,gCAYC;AAhBD,+CAAuD;AAGvD,6FAA6F;AACtF,KAAK,UAAU,UAAU,CAAC,MAAkB;IACjD,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAEnC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC7D,UAAU,IAAI,KAAK,CAAC;IACtB,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,yEAAyE;AACzE,SAAS,kBAAkB,CAAC,QAAmB;IAC7C,OAAO,QAAQ;SACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,WAAW,KAAK,SAAS,CAAC;SAC/C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,mEAAmE;AACnE,KAAK,UAAU,gBAAgB,CAC7B,QAAgB,EAChB,QAAmB;IAEnB,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,IAAA,mBAAQ,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,KAAK,SAAS;YAAE,SAAS;QACtD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;QACjC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,IAAI,KAAK,CAAC,MAAM;YAAE,SAAS;QAErD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAI,CAAC,WAAY,CAAC;QAC9C,KAAK,CAAC,OAAO,CAAC,GAAG,oBAAoB,CACnC,KAAK,CAAC,OAAO,CAAC,EACd,OAAO,CAAC,MAAM,GAAG,CAAC,EAClB,OAAO,CAAC,GAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,EAC/D,WAAW,CACZ,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,IAAA,oBAAS,EAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gEAAgE;AAChE,SAAS,oBAAoB,CAC3B,IAAY,EACZ,QAAgB,EAChB,MAA0B,EAC1B,WAAmB;IAEnB,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;IAClC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACjE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Programmatic API for aireview. */
|
|
2
|
+
export { scan } from './scanner/index.js';
|
|
3
|
+
export type { Severity, RuleCategory, Language, FixSuggestion, Finding, FileResult, ScanResult, ScanOptions, ParsedImport, FunctionCall, FunctionDecl, Comment, TypeAnnotation, CatchBlock, StringLiteral, ParserResult, Rule, RuleContext, AireviewConfig, } from './types.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,OAAO,EACP,UAAU,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,cAAc,EACd,UAAU,EACV,aAAa,EACb,YAAY,EACZ,IAAI,EACJ,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scan = void 0;
|
|
4
|
+
/** Programmatic API for aireview. */
|
|
5
|
+
var index_js_1 = require("./scanner/index.js");
|
|
6
|
+
Object.defineProperty(exports, "scan", { enumerable: true, get: function () { return index_js_1.scan; } });
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;AACrC,+CAA0C;AAAjC,gGAAA,IAAI,OAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ParserResult, Language } from '../types.js';
|
|
2
|
+
/** Get the supported file extensions. */
|
|
3
|
+
export declare function getSupportedExtensions(): string[];
|
|
4
|
+
/** Determine the language of a file by its extension. */
|
|
5
|
+
export declare function getLanguage(filePath: string): Language | null;
|
|
6
|
+
/** Parse a source file into a structured ParserResult. */
|
|
7
|
+
export declare function parseFile(source: string, filePath: string): ParserResult;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAoB1D,yCAAyC;AACzC,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAEjD;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAG7D;AAED,0DAA0D;AAC1D,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAOxE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSupportedExtensions = getSupportedExtensions;
|
|
4
|
+
exports.getLanguage = getLanguage;
|
|
5
|
+
exports.parseFile = parseFile;
|
|
6
|
+
const typescript_parser_js_1 = require("./typescript-parser.js");
|
|
7
|
+
const python_parser_js_1 = require("./python-parser.js");
|
|
8
|
+
/** Map of file extensions to their parser functions. */
|
|
9
|
+
const PARSER_MAP = {
|
|
10
|
+
'.ts': typescript_parser_js_1.parseTypeScript,
|
|
11
|
+
'.tsx': typescript_parser_js_1.parseTypeScript,
|
|
12
|
+
'.js': typescript_parser_js_1.parseTypeScript,
|
|
13
|
+
'.jsx': typescript_parser_js_1.parseTypeScript,
|
|
14
|
+
'.py': python_parser_js_1.parsePython,
|
|
15
|
+
};
|
|
16
|
+
/** Map of file extensions to their language identifier. */
|
|
17
|
+
const LANGUAGE_MAP = {
|
|
18
|
+
'.ts': 'typescript',
|
|
19
|
+
'.tsx': 'typescript',
|
|
20
|
+
'.js': 'javascript',
|
|
21
|
+
'.jsx': 'javascript',
|
|
22
|
+
'.py': 'python',
|
|
23
|
+
};
|
|
24
|
+
/** Get the supported file extensions. */
|
|
25
|
+
function getSupportedExtensions() {
|
|
26
|
+
return Object.keys(PARSER_MAP);
|
|
27
|
+
}
|
|
28
|
+
/** Determine the language of a file by its extension. */
|
|
29
|
+
function getLanguage(filePath) {
|
|
30
|
+
const ext = getExtension(filePath);
|
|
31
|
+
return LANGUAGE_MAP[ext] ?? null;
|
|
32
|
+
}
|
|
33
|
+
/** Parse a source file into a structured ParserResult. */
|
|
34
|
+
function parseFile(source, filePath) {
|
|
35
|
+
const ext = getExtension(filePath);
|
|
36
|
+
const parser = PARSER_MAP[ext];
|
|
37
|
+
if (!parser) {
|
|
38
|
+
throw new Error(`Unsupported file extension: ${ext}`);
|
|
39
|
+
}
|
|
40
|
+
return parser(source, filePath);
|
|
41
|
+
}
|
|
42
|
+
/** Extract the file extension from a path. */
|
|
43
|
+
function getExtension(filePath) {
|
|
44
|
+
const match = filePath.match(/\.[^.]+$/);
|
|
45
|
+
return match ? match[0] : '';
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":";;AAuBA,wDAEC;AAGD,kCAGC;AAGD,8BAOC;AAzCD,iEAAyD;AACzD,yDAAiD;AAGjD,wDAAwD;AACxD,MAAM,UAAU,GAAuE;IACrF,KAAK,EAAE,sCAAe;IACtB,MAAM,EAAE,sCAAe;IACvB,KAAK,EAAE,sCAAe;IACtB,MAAM,EAAE,sCAAe;IACvB,KAAK,EAAE,8BAAW;CACnB,CAAC;AAEF,2DAA2D;AAC3D,MAAM,YAAY,GAA6B;IAC7C,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,QAAQ;CAChB,CAAC;AAEF,yCAAyC;AACzC,SAAgB,sBAAsB;IACpC,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACjC,CAAC;AAED,yDAAyD;AACzD,SAAgB,WAAW,CAAC,QAAgB;IAC1C,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACnC,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;AACnC,CAAC;AAED,0DAA0D;AAC1D,SAAgB,SAAS,CAAC,MAAc,EAAE,QAAgB;IACxD,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,8CAA8C;AAC9C,SAAS,YAAY,CAAC,QAAgB;IACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python-parser.d.ts","sourceRoot":"","sources":["../../src/parsers/python-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAOV,YAAY,EAEb,MAAM,aAAa,CAAC;AAErB,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAc1E"}
|