@promise-inc/ai-guard 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/README.md +141 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +29 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +103 -0
- package/dist/config.js.map +1 -0
- package/dist/engine.d.ts +3 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +74 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/ai-patterns.d.ts +5 -0
- package/dist/rules/ai-patterns.d.ts.map +1 -0
- package/dist/rules/ai-patterns.js +94 -0
- package/dist/rules/ai-patterns.js.map +1 -0
- package/dist/rules/excessive-comments.d.ts +5 -0
- package/dist/rules/excessive-comments.d.ts.map +1 -0
- package/dist/rules/excessive-comments.js +41 -0
- package/dist/rules/excessive-comments.js.map +1 -0
- package/dist/rules/generic-names.d.ts +5 -0
- package/dist/rules/generic-names.d.ts.map +1 -0
- package/dist/rules/generic-names.js +61 -0
- package/dist/rules/generic-names.js.map +1 -0
- package/dist/rules/index.d.ts +8 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +49 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/large-functions.d.ts +5 -0
- package/dist/rules/large-functions.d.ts.map +1 -0
- package/dist/rules/large-functions.js +58 -0
- package/dist/rules/large-functions.js.map +1 -0
- package/dist/rules/obvious-comments.d.ts +5 -0
- package/dist/rules/obvious-comments.d.ts.map +1 -0
- package/dist/rules/obvious-comments.js +111 -0
- package/dist/rules/obvious-comments.js.map +1 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +43 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/files.d.ts +4 -0
- package/dist/utils/files.d.ts.map +1 -0
- package/dist/utils/files.js +85 -0
- package/dist/utils/files.js.map +1 -0
- package/dist/utils/output.d.ts +3 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +43 -0
- package/dist/utils/output.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# @promise-inc/ai-guard
|
|
2
|
+
|
|
3
|
+
Detect AI-generated code patterns before commit/push. Not a linter — a guard.
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="https://raw.githubusercontent.com/promise-inc/ai-guard/main/assets/demo.svg" alt="ai-guard CLI output demo" width="680" />
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<img src="https://raw.githubusercontent.com/promise-inc/ai-guard/main/assets/usage.svg" alt="ai-guard config example" width="680" />
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
## Why?
|
|
14
|
+
|
|
15
|
+
AI tools generate code that works but often carries patterns that degrade codebases over time:
|
|
16
|
+
|
|
17
|
+
- Excessive comments that restate the obvious
|
|
18
|
+
- Generic variable names (`data`, `result`, `item`)
|
|
19
|
+
- Functions that are way too large
|
|
20
|
+
- `// Step 1:` style comments
|
|
21
|
+
- Verbose JSDoc blocks with no real information
|
|
22
|
+
|
|
23
|
+
`ai-guard` catches these patterns **before they reach your codebase**.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @promise-inc/ai-guard --save-dev
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Analyze the entire project
|
|
35
|
+
npx ai-guard
|
|
36
|
+
|
|
37
|
+
# Analyze only staged files (for pre-commit hooks)
|
|
38
|
+
npx ai-guard --staged
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### As a Git Hook
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"husky": {
|
|
46
|
+
"hooks": {
|
|
47
|
+
"pre-push": "ai-guard"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or with `lint-staged`:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"lint-staged": {
|
|
58
|
+
"*.{ts,tsx,js,jsx}": "ai-guard --staged"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Rules
|
|
64
|
+
|
|
65
|
+
| Rule | What it detects | Severity |
|
|
66
|
+
|------|----------------|----------|
|
|
67
|
+
| `excessive-comments` | Files where comment ratio exceeds threshold | error |
|
|
68
|
+
| `obvious-comments` | Redundant comments like `// Initialize the result` | warning |
|
|
69
|
+
| `generic-names` | Variables/functions named `data`, `result`, `item`, etc. | warning |
|
|
70
|
+
| `large-functions` | Functions exceeding the line limit | error |
|
|
71
|
+
| `ai-patterns` | `// Step 1:`, `// Helper function`, verbose JSDoc, forbidden text patterns | warning/error |
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
Create `ai-guard.config.ts`, `ai-guard.config.js`, or add an `ai-guard` field to `package.json`:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
export default {
|
|
79
|
+
maxCommentsRatio: 0.15,
|
|
80
|
+
maxFunctionLines: 60,
|
|
81
|
+
forbidGenericNames: ["data", "result", "item", "value", "temp"],
|
|
82
|
+
aiPatterns: {
|
|
83
|
+
forbid: [
|
|
84
|
+
"this function",
|
|
85
|
+
"the purpose of",
|
|
86
|
+
"we will",
|
|
87
|
+
"this method",
|
|
88
|
+
"note that",
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
include: ["**/*.ts", "**/*.tsx"],
|
|
92
|
+
exclude: ["node_modules/**", "dist/**", "**/*.test.*"],
|
|
93
|
+
};
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Config Options
|
|
97
|
+
|
|
98
|
+
| Option | Type | Default | Description |
|
|
99
|
+
|--------|------|---------|-------------|
|
|
100
|
+
| `maxCommentsRatio` | `number` | `0.15` | Max ratio of comment lines to total lines |
|
|
101
|
+
| `maxFunctionLines` | `number` | `60` | Max lines per function/method |
|
|
102
|
+
| `forbidGenericNames` | `string[]` | `["data", "result", ...]` | Banned variable/function names |
|
|
103
|
+
| `aiPatterns.forbid` | `string[]` | `["this function", ...]` | Forbidden phrases in comments |
|
|
104
|
+
| `include` | `string[]` | `["**/*.ts", "**/*.tsx", ...]` | File patterns to analyze |
|
|
105
|
+
| `exclude` | `string[]` | `["node_modules/**", ...]` | File patterns to skip |
|
|
106
|
+
|
|
107
|
+
## Programmatic API
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { analyzeProject, loadConfig } from '@promise-inc/ai-guard';
|
|
111
|
+
|
|
112
|
+
const config = await loadConfig(process.cwd());
|
|
113
|
+
const analysis = await analyzeProject(process.cwd(), config);
|
|
114
|
+
|
|
115
|
+
console.log(analysis.passed); // true | false
|
|
116
|
+
console.log(analysis.totalViolations); // number
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Exit Codes
|
|
120
|
+
|
|
121
|
+
| Code | Meaning |
|
|
122
|
+
|------|---------|
|
|
123
|
+
| `0` | All files passed |
|
|
124
|
+
| `1` | Violations found |
|
|
125
|
+
| `2` | Internal error |
|
|
126
|
+
|
|
127
|
+
## Design Principles
|
|
128
|
+
|
|
129
|
+
- **Fast** — AST-based analysis, no network calls
|
|
130
|
+
- **Deterministic** — Same input always produces same output
|
|
131
|
+
- **CI-friendly** — Exit codes, no interactive prompts
|
|
132
|
+
- **Zero external dependencies** — Only `ts-morph` for AST parsing
|
|
133
|
+
- **Not a linter** — Focused exclusively on AI-generated code patterns
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
Developed by [Promise Inc.](https://promise.codes)
|
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,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const config_1 = require("./config");
|
|
5
|
+
const engine_1 = require("./engine");
|
|
6
|
+
const files_1 = require("./utils/files");
|
|
7
|
+
const output_1 = require("./utils/output");
|
|
8
|
+
async function main() {
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
const staged = args.includes('--staged');
|
|
11
|
+
const cwd = process.cwd();
|
|
12
|
+
const config = await (0, config_1.loadConfig)(cwd);
|
|
13
|
+
let stagedFiles;
|
|
14
|
+
if (staged) {
|
|
15
|
+
stagedFiles = await (0, files_1.getStagedFiles)();
|
|
16
|
+
if (stagedFiles.length === 0) {
|
|
17
|
+
console.log('\nai-guard: No staged files to analyze.\n');
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const analysis = await (0, engine_1.analyzeProject)(cwd, config, stagedFiles);
|
|
22
|
+
console.log((0, output_1.formatResult)(analysis));
|
|
23
|
+
process.exit(analysis.passed ? 0 : 1);
|
|
24
|
+
}
|
|
25
|
+
main().catch((err) => {
|
|
26
|
+
console.error('ai-guard error:', err);
|
|
27
|
+
process.exit(2);
|
|
28
|
+
});
|
|
29
|
+
//# 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":";;;AAEA,qCAAsC;AACtC,qCAA0C;AAC1C,yCAA+C;AAC/C,2CAA8C;AAE9C,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE1B,MAAM,MAAM,GAAG,MAAM,IAAA,mBAAU,EAAC,GAAG,CAAC,CAAC;IAErC,IAAI,WAAiC,CAAC;IACtC,IAAI,MAAM,EAAE,CAAC;QACX,WAAW,GAAG,MAAM,IAAA,sBAAc,GAAE,CAAC;QACrC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;YACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,IAAA,uBAAc,EAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAEhE,OAAO,CAAC,GAAG,CAAC,IAAA,qBAAY,EAAC,QAAQ,CAAC,CAAC,CAAC;IAEpC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAkB,MAAM,SAAS,CAAC;AAgDxD,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,aAAa,CAAC,CAYpF"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadConfig = loadConfig;
|
|
37
|
+
const fs = __importStar(require("fs/promises"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const types_1 = require("./types");
|
|
40
|
+
const CONFIG_FILES = [
|
|
41
|
+
'ai-guard.config.ts',
|
|
42
|
+
'ai-guard.config.js',
|
|
43
|
+
];
|
|
44
|
+
async function fileExists(filePath) {
|
|
45
|
+
try {
|
|
46
|
+
await fs.access(filePath);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function loadFromPackageJson(cwd) {
|
|
54
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
55
|
+
if (!(await fileExists(pkgPath)))
|
|
56
|
+
return null;
|
|
57
|
+
const content = await fs.readFile(pkgPath, 'utf-8');
|
|
58
|
+
const pkg = JSON.parse(content);
|
|
59
|
+
return pkg['ai-guard'] ?? null;
|
|
60
|
+
}
|
|
61
|
+
async function loadFromConfigFile(cwd) {
|
|
62
|
+
for (const configFile of CONFIG_FILES) {
|
|
63
|
+
const configPath = path.join(cwd, configFile);
|
|
64
|
+
if (await fileExists(configPath)) {
|
|
65
|
+
const absolutePath = path.resolve(configPath);
|
|
66
|
+
if (configFile.endsWith('.ts')) {
|
|
67
|
+
try {
|
|
68
|
+
require('ts-node/register/transpile-only');
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// ts-node not available — skip .ts config
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
76
|
+
const mod = require(absolutePath);
|
|
77
|
+
return mod.default ?? mod;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
async function loadConfig(cwd = process.cwd()) {
|
|
83
|
+
const fromFile = await loadFromConfigFile(cwd);
|
|
84
|
+
if (fromFile) {
|
|
85
|
+
return mergeConfig(fromFile);
|
|
86
|
+
}
|
|
87
|
+
const fromPkg = await loadFromPackageJson(cwd);
|
|
88
|
+
if (fromPkg) {
|
|
89
|
+
return mergeConfig(fromPkg);
|
|
90
|
+
}
|
|
91
|
+
return { ...types_1.DEFAULT_CONFIG };
|
|
92
|
+
}
|
|
93
|
+
function mergeConfig(partial) {
|
|
94
|
+
return {
|
|
95
|
+
...types_1.DEFAULT_CONFIG,
|
|
96
|
+
...partial,
|
|
97
|
+
aiPatterns: {
|
|
98
|
+
...types_1.DEFAULT_CONFIG.aiPatterns,
|
|
99
|
+
...partial.aiPatterns,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,gCAYC;AA9DD,gDAAkC;AAClC,2CAA6B;AAC7B,mCAAwD;AAExD,MAAM,YAAY,GAAG;IACnB,oBAAoB;IACpB,oBAAoB;CACrB,CAAC;AAEF,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,GAAW;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC/C,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,OAAO,GAAG,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC;AACjC,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAC3C,KAAK,MAAM,UAAU,IAAI,YAAY,EAAE,CAAC;QACtC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAC9C,IAAI,MAAM,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACjC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAE9C,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC;oBACH,OAAO,CAAC,iCAAiC,CAAC,CAAC;gBAC7C,CAAC;gBAAC,MAAM,CAAC;oBACP,0CAA0C;oBAC1C,SAAS;gBACX,CAAC;YACH,CAAC;YAED,iEAAiE;YACjE,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;YAClC,OAAO,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAEM,KAAK,UAAU,UAAU,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAC1D,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,EAAE,GAAG,sBAAc,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,WAAW,CAAC,OAA+B;IAClD,OAAO;QACL,GAAG,sBAAc;QACjB,GAAG,OAAO;QACV,UAAU,EAAE;YACV,GAAG,sBAAc,CAAC,UAAU;YAC5B,GAAG,OAAO,CAAC,UAAU;SACtB;KACF,CAAC;AACJ,CAAC"}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAgB,MAAM,SAAS,CAAC;AAItE,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,aAAa,EACrB,WAAW,CAAC,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC,cAAc,CAAC,CAoCzB"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.analyzeProject = analyzeProject;
|
|
37
|
+
const fs = __importStar(require("fs/promises"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const rules_1 = require("./rules");
|
|
40
|
+
const files_1 = require("./utils/files");
|
|
41
|
+
async function analyzeProject(cwd, config, stagedFiles) {
|
|
42
|
+
const files = stagedFiles ?? await (0, files_1.resolveFiles)(cwd, config);
|
|
43
|
+
const results = [];
|
|
44
|
+
for (const file of files) {
|
|
45
|
+
const absolutePath = path.isAbsolute(file) ? file : path.join(cwd, file);
|
|
46
|
+
try {
|
|
47
|
+
await fs.access(absolutePath);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const violations = rules_1.ALL_RULES.flatMap((rule) => {
|
|
53
|
+
try {
|
|
54
|
+
return rule.analyze(absolutePath, config);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
if (violations.length > 0) {
|
|
61
|
+
results.push({
|
|
62
|
+
filePath: path.relative(cwd, absolutePath),
|
|
63
|
+
violations,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const totalViolations = results.reduce((sum, r) => sum + r.violations.length, 0);
|
|
68
|
+
return {
|
|
69
|
+
files: results,
|
|
70
|
+
totalViolations,
|
|
71
|
+
passed: totalViolations === 0,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,wCAwCC;AA9CD,gDAAkC;AAClC,2CAA6B;AAE7B,mCAAoC;AACpC,yCAA6C;AAEtC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,MAAqB,EACrB,WAAsB;IAEtB,MAAM,KAAK,GAAG,WAAW,IAAI,MAAM,IAAA,oBAAY,EAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAmB,EAAE,CAAC;IAEnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAEzE,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GAAG,iBAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAC5C,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC;gBACX,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;gBAC1C,UAAU;aACX,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAEjF,OAAO;QACL,KAAK,EAAE,OAAO;QACd,eAAe;QACf,MAAM,EAAE,eAAe,KAAK,CAAC;KAC9B,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { loadConfig } from './config';
|
|
2
|
+
export { analyzeProject } from './engine';
|
|
3
|
+
export { ALL_RULES } from './rules';
|
|
4
|
+
export type { AiGuardConfig, Violation, FileAnalysis, AnalysisResult, Rule, } from './types';
|
|
5
|
+
export { DEFAULT_CONFIG } from './types';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,YAAY,EACV,aAAa,EACb,SAAS,EACT,YAAY,EACZ,cAAc,EACd,IAAI,GACL,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_CONFIG = exports.ALL_RULES = exports.analyzeProject = exports.loadConfig = void 0;
|
|
4
|
+
var config_1 = require("./config");
|
|
5
|
+
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
|
|
6
|
+
var engine_1 = require("./engine");
|
|
7
|
+
Object.defineProperty(exports, "analyzeProject", { enumerable: true, get: function () { return engine_1.analyzeProject; } });
|
|
8
|
+
var rules_1 = require("./rules");
|
|
9
|
+
Object.defineProperty(exports, "ALL_RULES", { enumerable: true, get: function () { return rules_1.ALL_RULES; } });
|
|
10
|
+
var types_1 = require("./types");
|
|
11
|
+
Object.defineProperty(exports, "DEFAULT_CONFIG", { enumerable: true, get: function () { return types_1.DEFAULT_CONFIG; } });
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AAA7B,oGAAA,UAAU,OAAA;AACnB,mCAA0C;AAAjC,wGAAA,cAAc,OAAA;AACvB,iCAAoC;AAA3B,kGAAA,SAAS,OAAA;AAQlB,iCAAyC;AAAhC,uGAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AiGuardConfig, Violation } from '../types';
|
|
2
|
+
export declare const name = "ai-patterns";
|
|
3
|
+
export declare const description = "Detects textual patterns commonly found in AI-generated code";
|
|
4
|
+
export declare function analyze(filePath: string, config: AiGuardConfig): Violation[];
|
|
5
|
+
//# sourceMappingURL=ai-patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-patterns.d.ts","sourceRoot":"","sources":["../../src/rules/ai-patterns.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEpD,eAAO,MAAM,IAAI,gBAAgB,CAAC;AAClC,eAAO,MAAM,WAAW,iEAAiE,CAAC;AAkD1F,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,SAAS,EAAE,CAQ5E"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.description = exports.name = void 0;
|
|
37
|
+
exports.analyze = analyze;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
exports.name = 'ai-patterns';
|
|
40
|
+
exports.description = 'Detects textual patterns commonly found in AI-generated code';
|
|
41
|
+
const CODE_AI_PATTERNS = [
|
|
42
|
+
/\/\/\s*Step\s+\d+/i,
|
|
43
|
+
/\/\/\s*-{3,}/,
|
|
44
|
+
/\/\/\s*={3,}/,
|
|
45
|
+
/\/\/\s*#{3,}/,
|
|
46
|
+
/\/\*\*[\s\S]*?@description\s+This\s+(function|method|class)/i,
|
|
47
|
+
/\/\/\s*Helper\s+(function|method)\s+/i,
|
|
48
|
+
/\/\/\s*Utility\s+(function|method)\s+/i,
|
|
49
|
+
/\/\/\s*Main\s+(function|logic)\s+/i,
|
|
50
|
+
];
|
|
51
|
+
function findCodePatterns(lines, filePath) {
|
|
52
|
+
const violations = [];
|
|
53
|
+
for (let i = 0; i < lines.length; i++) {
|
|
54
|
+
for (const pattern of CODE_AI_PATTERNS) {
|
|
55
|
+
if (pattern.test(lines[i])) {
|
|
56
|
+
violations.push({
|
|
57
|
+
rule: exports.name,
|
|
58
|
+
file: filePath,
|
|
59
|
+
message: `AI-generated pattern detected: "${lines[i].trim()}"`,
|
|
60
|
+
line: i + 1,
|
|
61
|
+
severity: 'warning',
|
|
62
|
+
});
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return violations;
|
|
68
|
+
}
|
|
69
|
+
function findVerboseJsDoc(content, filePath) {
|
|
70
|
+
const blocks = content.match(/\/\*\*[\s\S]*?\*\//g) ?? [];
|
|
71
|
+
return blocks
|
|
72
|
+
.filter((block) => {
|
|
73
|
+
const lineCount = block.split('\n').length;
|
|
74
|
+
const hasOnlyBasicTags = /\*\s*@(param|returns|description)\s/.test(block) &&
|
|
75
|
+
!/@(throws|example|deprecated|see|link)/.test(block);
|
|
76
|
+
return lineCount > 8 && hasOnlyBasicTags;
|
|
77
|
+
})
|
|
78
|
+
.map((block) => ({
|
|
79
|
+
rule: exports.name,
|
|
80
|
+
file: filePath,
|
|
81
|
+
message: `Overly verbose JSDoc (${block.split('\n').length} lines)`,
|
|
82
|
+
line: content.substring(0, content.indexOf(block)).split('\n').length,
|
|
83
|
+
severity: 'warning',
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
function analyze(filePath, config) {
|
|
87
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
88
|
+
const lines = content.split('\n');
|
|
89
|
+
return [
|
|
90
|
+
...findCodePatterns(lines, filePath),
|
|
91
|
+
...findVerboseJsDoc(content, filePath),
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=ai-patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-patterns.js","sourceRoot":"","sources":["../../src/rules/ai-patterns.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,0BAQC;AA9DD,uCAAyB;AAGZ,QAAA,IAAI,GAAG,aAAa,CAAC;AACrB,QAAA,WAAW,GAAG,8DAA8D,CAAC;AAE1F,MAAM,gBAAgB,GAAG;IACvB,oBAAoB;IACpB,cAAc;IACd,cAAc;IACd,cAAc;IACd,8DAA8D;IAC9D,uCAAuC;IACvC,wCAAwC;IACxC,oCAAoC;CACrC,CAAC;AAEF,SAAS,gBAAgB,CAAC,KAAe,EAAE,QAAgB;IACzD,MAAM,UAAU,GAAgB,EAAE,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;YACvC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3B,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI,EAAE,YAAI;oBACV,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,mCAAmC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG;oBAC9D,IAAI,EAAE,CAAC,GAAG,CAAC;oBACX,QAAQ,EAAE,SAAS;iBACpB,CAAC,CAAC;gBACH,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe,EAAE,QAAgB;IACzD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,IAAI,EAAE,CAAC;IAC1D,OAAO,MAAM;SACV,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;QAChB,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QAC3C,MAAM,gBAAgB,GAAG,qCAAqC,CAAC,IAAI,CAAC,KAAK,CAAC;YACxE,CAAC,uCAAuC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvD,OAAO,SAAS,GAAG,CAAC,IAAI,gBAAgB,CAAC;IAC3C,CAAC,CAAC;SACD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACf,IAAI,EAAE,YAAI;QACV,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,yBAAyB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,SAAS;QACnE,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;QACrE,QAAQ,EAAE,SAAkB;KAC7B,CAAC,CAAC,CAAC;AACR,CAAC;AAED,SAAgB,OAAO,CAAC,QAAgB,EAAE,MAAqB;IAC7D,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,OAAO;QACL,GAAG,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC;QACpC,GAAG,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC;KACvC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AiGuardConfig, Violation } from '../types';
|
|
2
|
+
export declare const name = "excessive-comments";
|
|
3
|
+
export declare const description = "Detects files with too many comments relative to code";
|
|
4
|
+
export declare function analyze(filePath: string, config: AiGuardConfig): Violation[];
|
|
5
|
+
//# sourceMappingURL=excessive-comments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"excessive-comments.d.ts","sourceRoot":"","sources":["../../src/rules/excessive-comments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEpD,eAAO,MAAM,IAAI,uBAAuB,CAAC;AACzC,eAAO,MAAM,WAAW,0DAA0D,CAAC;AAEnF,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,SAAS,EAAE,CAuC5E"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.description = exports.name = void 0;
|
|
4
|
+
exports.analyze = analyze;
|
|
5
|
+
const ts_morph_1 = require("ts-morph");
|
|
6
|
+
exports.name = 'excessive-comments';
|
|
7
|
+
exports.description = 'Detects files with too many comments relative to code';
|
|
8
|
+
function analyze(filePath, config) {
|
|
9
|
+
const project = new ts_morph_1.Project({ skipAddingFilesFromTsConfig: true });
|
|
10
|
+
const sourceFile = project.addSourceFileAtPath(filePath);
|
|
11
|
+
const fullText = sourceFile.getFullText();
|
|
12
|
+
const lines = fullText.split('\n');
|
|
13
|
+
const totalLines = lines.filter((l) => l.trim().length > 0).length;
|
|
14
|
+
if (totalLines === 0)
|
|
15
|
+
return [];
|
|
16
|
+
let commentLines = 0;
|
|
17
|
+
// Count single-line comments
|
|
18
|
+
const leadingCommentRanges = sourceFile.getDescendantsOfKind(
|
|
19
|
+
// SyntaxKind values for comments aren't directly available via getDescendantsOfKind
|
|
20
|
+
// We'll use regex on the full text instead
|
|
21
|
+
0);
|
|
22
|
+
void leadingCommentRanges;
|
|
23
|
+
// Regex-based counting (more reliable for comment ratio)
|
|
24
|
+
for (const line of lines) {
|
|
25
|
+
const trimmed = line.trim();
|
|
26
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*') || trimmed.startsWith('*/')) {
|
|
27
|
+
commentLines++;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const ratio = commentLines / totalLines;
|
|
31
|
+
if (ratio > config.maxCommentsRatio) {
|
|
32
|
+
return [{
|
|
33
|
+
rule: exports.name,
|
|
34
|
+
file: filePath,
|
|
35
|
+
message: `Excessive comments (${Math.round(ratio * 100)}% — max ${Math.round(config.maxCommentsRatio * 100)}%)`,
|
|
36
|
+
severity: 'error',
|
|
37
|
+
}];
|
|
38
|
+
}
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=excessive-comments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"excessive-comments.js","sourceRoot":"","sources":["../../src/rules/excessive-comments.ts"],"names":[],"mappings":";;;AAMA,0BAuCC;AA7CD,uCAAmC;AAGtB,QAAA,IAAI,GAAG,oBAAoB,CAAC;AAC5B,QAAA,WAAW,GAAG,uDAAuD,CAAC;AAEnF,SAAgB,OAAO,CAAC,QAAgB,EAAE,MAAqB;IAC7D,MAAM,OAAO,GAAG,IAAI,kBAAO,CAAC,EAAE,2BAA2B,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,MAAM,UAAU,GAAG,OAAO,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IAEnE,IAAI,UAAU,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhC,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,6BAA6B;IAC7B,MAAM,oBAAoB,GAAG,UAAU,CAAC,oBAAoB;IAC1D,oFAAoF;IACpF,2CAA2C;IAC3C,CAAC,CACF,CAAC;IACF,KAAK,oBAAoB,CAAC;IAE1B,yDAAyD;IACzD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAChH,YAAY,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,GAAG,UAAU,CAAC;IAExC,IAAI,KAAK,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC;QACpC,OAAO,CAAC;gBACN,IAAI,EAAE,YAAI;gBACV,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,uBAAuB,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,GAAG,GAAG,CAAC,IAAI;gBAC/G,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AiGuardConfig, Violation } from '../types';
|
|
2
|
+
export declare const name = "generic-names";
|
|
3
|
+
export declare const description = "Detects generic variable/function names typical of AI-generated code";
|
|
4
|
+
export declare function analyze(filePath: string, config: AiGuardConfig): Violation[];
|
|
5
|
+
//# sourceMappingURL=generic-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-names.d.ts","sourceRoot":"","sources":["../../src/rules/generic-names.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEpD,eAAO,MAAM,IAAI,kBAAkB,CAAC;AACpC,eAAO,MAAM,WAAW,yEAAyE,CAAC;AAElG,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,SAAS,EAAE,CA0D5E"}
|