pr-checkmate 1.22.7 → 1.23.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 +101 -333
- package/cspell.json +9 -1
- package/dist/cli.js +32 -2
- package/dist/config/constants.d.ts +25 -1
- package/dist/config/constants.js +157 -38
- package/dist/config/index.d.ts +15 -2
- package/dist/config/index.js +28 -7
- package/dist/config/loader.js +5 -1
- package/dist/core/checks/dependencies/banned-imports.d.ts +2 -0
- package/dist/core/checks/dependencies/banned-imports.js +71 -0
- package/dist/core/checks/{circular-deps.d.ts → dependencies/circular-deps.d.ts} +1 -1
- package/dist/core/checks/{circular-deps.js → dependencies/circular-deps.js} +9 -10
- package/dist/core/checks/{dependency-check.d.ts → dependencies/dependency-check.d.ts} +1 -1
- package/dist/core/checks/{dependency-check.js → dependencies/dependency-check.js} +3 -3
- package/dist/core/checks/{license-check.d.ts → dependencies/license-check.d.ts} +1 -1
- package/dist/core/checks/{license-check.js → dependencies/license-check.js} +3 -3
- package/dist/core/checks/{npm-audit.d.ts → dependencies/npm-audit.d.ts} +1 -1
- package/dist/core/checks/{npm-audit.js → dependencies/npm-audit.js} +3 -3
- package/dist/core/checks/{outdated-deps.d.ts → dependencies/outdated-deps.d.ts} +1 -1
- package/dist/core/checks/{outdated-deps.js → dependencies/outdated-deps.js} +3 -3
- package/dist/core/checks/dependencies/vuln-scan.d.ts +9 -0
- package/dist/core/checks/dependencies/vuln-scan.js +41 -0
- package/dist/core/checks/findings.d.ts +37 -1
- package/dist/core/checks/findings.js +80 -3
- package/dist/core/checks/git/custom-rules.d.ts +2 -0
- package/dist/core/checks/git/custom-rules.js +102 -0
- package/dist/core/checks/{diff-smell.d.ts → git/diff-smell.d.ts} +1 -1
- package/dist/core/checks/{diff-smell.js → git/diff-smell.js} +3 -3
- package/dist/core/checks/git/large-files.d.ts +2 -0
- package/dist/core/checks/git/large-files.js +83 -0
- package/dist/core/checks/git/leftover-debug.d.ts +2 -0
- package/dist/core/checks/git/leftover-debug.js +77 -0
- package/dist/core/checks/git/lockfile-drift.d.ts +2 -0
- package/dist/core/checks/git/lockfile-drift.js +114 -0
- package/dist/core/checks/git/merge-conflict.d.ts +2 -0
- package/dist/core/checks/git/merge-conflict.js +109 -0
- package/dist/core/checks/git/missing-tests.d.ts +2 -0
- package/dist/core/checks/git/missing-tests.js +92 -0
- package/dist/core/checks/git/todo-fixme.d.ts +7 -0
- package/dist/core/checks/git/todo-fixme.js +74 -0
- package/dist/core/checks/{cpp-format.d.ts → languages/cpp-format.d.ts} +1 -1
- package/dist/core/checks/{cpp-format.js → languages/cpp-format.js} +3 -3
- package/dist/core/checks/languages/csharp-format.d.ts +13 -0
- package/dist/core/checks/languages/csharp-format.js +52 -0
- package/dist/core/checks/languages/go-format.d.ts +8 -0
- package/dist/core/checks/languages/go-format.js +48 -0
- package/dist/core/checks/languages/go-lint.d.ts +8 -0
- package/dist/core/checks/languages/go-lint.js +48 -0
- package/dist/core/checks/{kotlin-lint.d.ts → languages/kotlin-lint.d.ts} +1 -1
- package/dist/core/checks/{kotlin-lint.js → languages/kotlin-lint.js} +13 -17
- package/dist/core/checks/{lint.d.ts → languages/lint.d.ts} +1 -1
- package/dist/core/checks/{lint.js → languages/lint.js} +25 -14
- package/dist/core/checks/languages/php-format.d.ts +9 -0
- package/dist/core/checks/languages/php-format.js +49 -0
- package/dist/core/checks/{prettier.d.ts → languages/prettier.d.ts} +1 -1
- package/dist/core/checks/{prettier.js → languages/prettier.js} +10 -10
- package/dist/core/checks/{python-format.d.ts → languages/python-format.d.ts} +1 -1
- package/dist/core/checks/{python-format.js → languages/python-format.js} +3 -3
- package/dist/core/checks/{python-lint.d.ts → languages/python-lint.d.ts} +1 -1
- package/dist/core/checks/{python-lint.js → languages/python-lint.js} +3 -3
- package/dist/core/checks/languages/python-typecheck.d.ts +9 -0
- package/dist/core/checks/languages/python-typecheck.js +66 -0
- package/dist/core/checks/languages/ruby-lint.d.ts +8 -0
- package/dist/core/checks/languages/ruby-lint.js +50 -0
- package/dist/core/checks/languages/rust-format.d.ts +9 -0
- package/dist/core/checks/languages/rust-format.js +45 -0
- package/dist/core/checks/languages/rust-lint.d.ts +8 -0
- package/dist/core/checks/languages/rust-lint.js +50 -0
- package/dist/core/checks/{swift-lint.d.ts → languages/swift-lint.d.ts} +1 -1
- package/dist/core/checks/{swift-lint.js → languages/swift-lint.js} +13 -17
- package/dist/core/checks/{typecheck.d.ts → languages/typecheck.d.ts} +1 -1
- package/dist/core/checks/{typecheck.js → languages/typecheck.js} +3 -3
- package/dist/core/checks/{commitlint.d.ts → pr/commitlint.d.ts} +1 -1
- package/dist/core/checks/{commitlint.js → pr/commitlint.js} +4 -4
- package/dist/core/checks/{pr-body.d.ts → pr/pr-body.d.ts} +1 -1
- package/dist/core/checks/{pr-body.js → pr/pr-body.js} +2 -2
- package/dist/core/checks/{pr-size-check.d.ts → pr/pr-size-check.d.ts} +1 -1
- package/dist/core/checks/{pr-size-check.js → pr/pr-size-check.js} +13 -11
- package/dist/core/checks/{pr-title-lint.d.ts → pr/pr-title-lint.d.ts} +1 -1
- package/dist/core/checks/{pr-title-lint.js → pr/pr-title-lint.js} +2 -2
- package/dist/core/checks/quality/case-collision.d.ts +8 -0
- package/dist/core/checks/quality/case-collision.js +40 -0
- package/dist/core/checks/quality/config-validation.d.ts +8 -0
- package/dist/core/checks/quality/config-validation.js +63 -0
- package/dist/core/checks/quality/coverage.d.ts +2 -0
- package/dist/core/checks/quality/coverage.js +63 -0
- package/dist/core/checks/{dead-code.d.ts → quality/dead-code.d.ts} +1 -1
- package/dist/core/checks/{dead-code.js → quality/dead-code.js} +4 -4
- package/dist/core/checks/{duplicate-check.d.ts → quality/duplicate-check.d.ts} +1 -1
- package/dist/core/checks/{duplicate-check.js → quality/duplicate-check.js} +11 -15
- package/dist/core/checks/quality/license-header.d.ts +7 -0
- package/dist/core/checks/quality/license-header.js +74 -0
- package/dist/core/checks/{markdown-lint.d.ts → quality/markdown-lint.d.ts} +1 -1
- package/dist/core/checks/{markdown-lint.js → quality/markdown-lint.js} +8 -21
- package/dist/core/checks/{spellcheck.d.ts → quality/spellcheck.d.ts} +1 -1
- package/dist/core/checks/{spellcheck.js → quality/spellcheck.js} +11 -19
- package/dist/core/checks/{diff-security.d.ts → security/diff-security.d.ts} +1 -1
- package/dist/core/checks/security/diff-security.js +262 -0
- package/dist/core/checks/security/dockerfile-security.d.ts +2 -0
- package/dist/core/checks/security/dockerfile-security.js +92 -0
- package/dist/core/checks/security/migration-safety.d.ts +2 -0
- package/dist/core/checks/security/migration-safety.js +110 -0
- package/dist/core/checks/{security.d.ts → security/security.d.ts} +1 -1
- package/dist/core/checks/{security.js → security/security.js} +4 -4
- package/dist/core/checks/{sensitive-file-guard.d.ts → security/sensitive-file-guard.d.ts} +1 -1
- package/dist/core/checks/{sensitive-file-guard.js → security/sensitive-file-guard.js} +4 -4
- package/dist/core/checks/security/workflow-security.d.ts +2 -0
- package/dist/core/checks/security/workflow-security.js +75 -0
- package/dist/core/context.js +54 -10
- package/dist/core/registry.js +73 -28
- package/dist/core/reporters.d.ts +4 -3
- package/dist/core/reporters.js +104 -4
- package/dist/core/run-checks.js +21 -3
- package/dist/core/targets.d.ts +17 -1
- package/dist/core/targets.js +74 -4
- package/dist/core/types.d.ts +13 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/init.js +86 -8
- package/dist/interfaces/index.d.ts +101 -1
- package/dist/scripts/copy-configs.js +6 -1
- package/dist/utils/detect-language.d.ts +1 -1
- package/dist/utils/detect-language.js +32 -3
- package/dist/utils/glob.d.ts +10 -0
- package/dist/utils/glob.js +25 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/eslint-default-rules.json +62 -0
- package/eslint.config.mjs +6 -66
- package/package.json +3 -1
- package/pr-checkmate.schema.json +166 -0
- package/src/config/cspell.json +9 -1
- package/src/config/eslint-default-rules.json +62 -0
- package/src/config/pr-checkmate.schema.json +166 -0
- package/dist/core/checks/diff-security.js +0 -145
- package/dist/utils/delta.d.ts +0 -5
- package/dist/utils/delta.js +0 -53
- package/src/config/eslint.config.mjs +0 -180
- /package/dist/core/checks/{ruff-shared.d.ts → languages/ruff-shared.d.ts} +0 -0
- /package/dist/core/checks/{ruff-shared.js → languages/ruff-shared.js} +0 -0
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.diffSecurityCheck = void 0;
|
|
4
|
-
const utils_1 = require("../../utils");
|
|
5
|
-
const types_1 = require("../types");
|
|
6
|
-
const findings_1 = require("./findings");
|
|
7
|
-
const SECURITY_PATTERNS = [
|
|
8
|
-
{
|
|
9
|
-
pattern: /^\+(?!\+).*dangerouslySetInnerHTML\s*=/,
|
|
10
|
-
label: 'dangerouslySetInnerHTML (XSS risk)',
|
|
11
|
-
severity: 'error',
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
pattern: /^\+(?!\+).*\.innerHTML\s*=/,
|
|
15
|
-
label: 'innerHTML assignment (XSS risk)',
|
|
16
|
-
severity: 'warn',
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
pattern: /^\+(?!\+).*document\.write\s*\(/,
|
|
20
|
-
label: 'document.write() (XSS risk)',
|
|
21
|
-
severity: 'error',
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
pattern: /^\+(?!\+)(?![^'"`]*['"`]).*\beval\s*\(/,
|
|
25
|
-
label: 'eval() (code injection risk)',
|
|
26
|
-
severity: 'error',
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
pattern: /^\+(?!\+).*\bnew\s+Function\s*\(/,
|
|
30
|
-
label: 'new Function() (code injection risk)',
|
|
31
|
-
severity: 'error',
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
pattern: /^\+(?!\+).*__proto__\s*[=:[]/,
|
|
35
|
-
label: '__proto__ mutation (prototype pollution)',
|
|
36
|
-
severity: 'error',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
pattern: /^\+(?!\+).*\.constructor\.prototype\b/,
|
|
40
|
-
label: 'constructor.prototype access (prototype pollution)',
|
|
41
|
-
severity: 'warn',
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
pattern: /^\+(?!\+).*createHash\s*\(\s*['"]md5['"]/,
|
|
45
|
-
label: 'MD5 (weak hash — use sha256 or stronger)',
|
|
46
|
-
severity: 'warn',
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
pattern: /^\+(?!\+).*createHash\s*\(\s*['"]sha1['"]/,
|
|
50
|
-
label: 'SHA-1 (weak hash — use sha256 or stronger)',
|
|
51
|
-
severity: 'warn',
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
pattern: /^\+(?!\+).*\bcreateDecipher\s*\(/,
|
|
55
|
-
label: 'deprecated createDecipher() — use createDecipheriv()',
|
|
56
|
-
severity: 'warn',
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
pattern: /^\+(?!\+).*\bcreateCipher\s*\(/,
|
|
60
|
-
label: 'deprecated createCipher() — use createCipheriv()',
|
|
61
|
-
severity: 'warn',
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
pattern: /^\+(?!\+).*cors\s*\(\s*\{[^}]*origin\s*:\s*['"]\*['"]/,
|
|
65
|
-
label: "CORS wildcard origin: '*' (allows any domain)",
|
|
66
|
-
severity: 'warn',
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
pattern: /^\+(?!\+).*['"]Access-Control-Allow-Origin['"]\s*[,:]\s*['"]\*['"]/,
|
|
70
|
-
label: "Access-Control-Allow-Origin: '*' header (CORS wildcard)",
|
|
71
|
-
severity: 'warn',
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
pattern: /^\+(?!\+).*(fetch|axios\.get|axios\.post|axios\.put|axios\.delete|http\.get|http\.request)\s*\(\s*['"]http:\/\//,
|
|
75
|
-
label: 'Insecure HTTP (non-HTTPS) in external call',
|
|
76
|
-
severity: 'warn',
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
pattern: /^\+(?!\+).*(exec|execSync|spawn|spawnSync)\s*\(\s*`[^`]*\$\{/,
|
|
80
|
-
label: 'exec/spawn with template literal (command injection risk)',
|
|
81
|
-
severity: 'error',
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
pattern: /^\+(?!\+).*(exec|execSync)\s*\(\s*['"][^'"]*['"\s]*\+/,
|
|
85
|
-
label: 'exec/spawn with string concatenation (command injection risk)',
|
|
86
|
-
severity: 'error',
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
pattern: /^\+(?!\+).*\b(query|execute|raw)\s*\(\s*`[^`]*\$\{/,
|
|
90
|
-
label: 'SQL query with template literal interpolation (SQL injection risk)',
|
|
91
|
-
severity: 'error',
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
// A quoted string that contains a whole SQL keyword, concatenated with a
|
|
95
|
-
// variable — the real injection shape. Word boundaries + the quote context
|
|
96
|
-
// stop identifiers like `insertions + deletions` from false-positiving.
|
|
97
|
-
pattern: /^\+(?!\+).*['"`][^'"`]*\b(SELECT|INSERT|UPDATE|DELETE|WHERE)\b[^'"`]*['"`]\s*\+\s*\w/i,
|
|
98
|
-
label: 'SQL string concatenation (SQL injection risk)',
|
|
99
|
-
severity: 'error',
|
|
100
|
-
},
|
|
101
|
-
];
|
|
102
|
-
/** Bucket added-line matches by severity, keyed by pattern label. */
|
|
103
|
-
function scanDiff(stdout) {
|
|
104
|
-
const errors = {};
|
|
105
|
-
const warnings = {};
|
|
106
|
-
for (const line of stdout.split('\n')) {
|
|
107
|
-
for (const { pattern, label, severity } of SECURITY_PATTERNS) {
|
|
108
|
-
if (pattern.test(line)) {
|
|
109
|
-
const bucket = severity === 'error' ? errors : warnings;
|
|
110
|
-
(bucket[label] ?? (bucket[label] = [])).push(line.slice(1).trim().substring(0, 120));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return { errors, warnings };
|
|
115
|
-
}
|
|
116
|
-
exports.diffSecurityCheck = {
|
|
117
|
-
name: 'Diff Security',
|
|
118
|
-
phase: 'informational',
|
|
119
|
-
applies(ctx) {
|
|
120
|
-
return ctx.config.diffSecurity?.enabled !== false && Boolean(ctx.baseSha);
|
|
121
|
-
},
|
|
122
|
-
async run(ctx) {
|
|
123
|
-
try {
|
|
124
|
-
const stdout = await (0, findings_1.diffAddedLines)(ctx, [
|
|
125
|
-
'*.ts',
|
|
126
|
-
'*.tsx',
|
|
127
|
-
'*.js',
|
|
128
|
-
'*.jsx',
|
|
129
|
-
'*.mjs',
|
|
130
|
-
'*.cjs',
|
|
131
|
-
]);
|
|
132
|
-
const { errors, warnings } = scanDiff(stdout);
|
|
133
|
-
return (0, findings_1.reportSeverityBuckets)(errors, warnings, {
|
|
134
|
-
prefix: 'Diff Security',
|
|
135
|
-
errorSummary: n => `${n} issue(s)`,
|
|
136
|
-
warningSummary: n => `${n} warning(s)`,
|
|
137
|
-
sampleLimit: 3,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
catch (err) {
|
|
141
|
-
utils_1.logger.warn(`[Diff Security]: ⚠️ Could not analyze diff\n${err}`);
|
|
142
|
-
return (0, types_1.skip)('diff unavailable');
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
};
|
package/dist/utils/delta.d.ts
DELETED
package/dist/utils/delta.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
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.getChangedFiles = getChangedFiles;
|
|
7
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const execa_1 = require("./execa");
|
|
10
|
-
const logger_1 = require("./logger");
|
|
11
|
-
/**
|
|
12
|
-
* Returns list of changed files in the current PR filtered by extension.
|
|
13
|
-
* Returns null when not in a GitHub PR context (falls back to full-project scan).
|
|
14
|
-
*/
|
|
15
|
-
async function getChangedFiles(extensions) {
|
|
16
|
-
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
17
|
-
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
18
|
-
if (eventName !== 'pull_request' || !eventPath || !node_fs_1.default.existsSync(eventPath)) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
let baseSha = null;
|
|
22
|
-
try {
|
|
23
|
-
const event = JSON.parse(node_fs_1.default.readFileSync(eventPath, 'utf-8'));
|
|
24
|
-
baseSha = event?.pull_request?.base?.sha ?? null;
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
if (!baseSha)
|
|
30
|
-
return null;
|
|
31
|
-
try {
|
|
32
|
-
const { stdout } = await (0, execa_1.execa)('git', [
|
|
33
|
-
'diff',
|
|
34
|
-
'--name-only',
|
|
35
|
-
'--diff-filter=ACMR',
|
|
36
|
-
baseSha,
|
|
37
|
-
'HEAD',
|
|
38
|
-
]);
|
|
39
|
-
const files = stdout
|
|
40
|
-
.split('\n')
|
|
41
|
-
.map(f => f.trim())
|
|
42
|
-
.filter(f => f && extensions.some(ext => f.endsWith(ext)))
|
|
43
|
-
.map(f => node_path_1.default.join(process.cwd(), f));
|
|
44
|
-
if (files.length === 0)
|
|
45
|
-
return null;
|
|
46
|
-
logger_1.logger.info(`[delta]: 📂 Delta mode: checking ${files.length} changed file(s)`);
|
|
47
|
-
return files;
|
|
48
|
-
}
|
|
49
|
-
catch (err) {
|
|
50
|
-
logger_1.logger.warn(`[delta]: ⚠️ Could not get changed files, falling back to full scan\n${err}`);
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import tsPlugin from '@typescript-eslint/eslint-plugin';
|
|
4
|
-
import tsParser from '@typescript-eslint/parser';
|
|
5
|
-
import prettierPlugin from 'eslint-plugin-prettier';
|
|
6
|
-
import sonarjsPlugin from 'eslint-plugin-sonarjs';
|
|
7
|
-
import importPlugin from 'eslint-plugin-import-x';
|
|
8
|
-
import jsdocPlugin from 'eslint-plugin-jsdoc';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Default ESLint rules - can be exported for use in init.ts
|
|
12
|
-
*/
|
|
13
|
-
export const defaultRules = {
|
|
14
|
-
'no-console': 'warn',
|
|
15
|
-
'no-debugger': 'error',
|
|
16
|
-
'prefer-const': 'error',
|
|
17
|
-
'eqeqeq': ['error', 'always'],
|
|
18
|
-
'@typescript-eslint/no-unused-vars': [
|
|
19
|
-
'error',
|
|
20
|
-
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
|
21
|
-
],
|
|
22
|
-
'@typescript-eslint/explicit-function-return-type': ['warn'],
|
|
23
|
-
'@typescript-eslint/no-explicit-any': ['warn'],
|
|
24
|
-
'@typescript-eslint/no-floating-promises': ['error'],
|
|
25
|
-
'space-before-function-paren': 'off',
|
|
26
|
-
'operator-linebreak': 'off',
|
|
27
|
-
'max-len': ['warn', { code: 100 }],
|
|
28
|
-
'semi': ['error', 'always'],
|
|
29
|
-
'quotes': ['error', 'single', { avoidEscape: true }],
|
|
30
|
-
'object-curly-spacing': ['error', 'always'],
|
|
31
|
-
'space-infix-ops': 'error',
|
|
32
|
-
'keyword-spacing': ['error', { before: true, after: true }],
|
|
33
|
-
'padding-line-between-statements': [
|
|
34
|
-
'error',
|
|
35
|
-
{ blankLine: 'always', prev: 'block', next: '*' },
|
|
36
|
-
{ blankLine: 'always', prev: '*', next: 'return' },
|
|
37
|
-
],
|
|
38
|
-
// Complexity analysis (#61)
|
|
39
|
-
'sonarjs/cognitive-complexity': ['warn', 30],
|
|
40
|
-
'sonarjs/no-duplicate-string': ['warn', { threshold: 3 }],
|
|
41
|
-
'sonarjs/no-identical-functions': 'warn',
|
|
42
|
-
// Import ordering (#65)
|
|
43
|
-
'import/order': [
|
|
44
|
-
'warn',
|
|
45
|
-
{
|
|
46
|
-
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
|
|
47
|
-
alphabetize: { order: 'asc', caseInsensitive: true },
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
'import/no-duplicates': 'error',
|
|
51
|
-
// Documentation (#62)
|
|
52
|
-
'jsdoc/require-jsdoc': [
|
|
53
|
-
'warn',
|
|
54
|
-
{
|
|
55
|
-
publicOnly: true,
|
|
56
|
-
require: {
|
|
57
|
-
FunctionDeclaration: true,
|
|
58
|
-
MethodDefinition: true,
|
|
59
|
-
ClassDeclaration: true,
|
|
60
|
-
ArrowFunctionExpression: false,
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
'jsdoc/check-param-names': 'warn',
|
|
65
|
-
'jsdoc/check-tag-names': 'warn',
|
|
66
|
-
'jsdoc/check-types': 'warn',
|
|
67
|
-
'prettier/prettier': [
|
|
68
|
-
'error',
|
|
69
|
-
{
|
|
70
|
-
semi: true,
|
|
71
|
-
singleQuote: true,
|
|
72
|
-
bracketSpacing: true,
|
|
73
|
-
arrowParens: 'avoid',
|
|
74
|
-
printWidth: 100,
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Default ignore patterns
|
|
81
|
-
*/
|
|
82
|
-
const defaultIgnores = [
|
|
83
|
-
'**/node_modules/**',
|
|
84
|
-
'**/dist/**',
|
|
85
|
-
'**/.git/**',
|
|
86
|
-
'**/build/**',
|
|
87
|
-
'**/coverage/**',
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Load user's pr-checkmate.json from project root
|
|
92
|
-
* Works both when developing the package and when installed in node_modules
|
|
93
|
-
*/
|
|
94
|
-
function loadUserConfig() {
|
|
95
|
-
let currentDir = process.cwd();
|
|
96
|
-
let configPath = path.join(currentDir, 'pr-checkmate.json');
|
|
97
|
-
|
|
98
|
-
// If running from node_modules, find project root
|
|
99
|
-
if (currentDir.includes('node_modules')) {
|
|
100
|
-
const parts = currentDir.split(path.sep);
|
|
101
|
-
const nodeModulesIndex = parts.lastIndexOf('node_modules');
|
|
102
|
-
if (nodeModulesIndex > 0) {
|
|
103
|
-
currentDir = parts.slice(0, nodeModulesIndex).join(path.sep);
|
|
104
|
-
configPath = path.join(currentDir, 'pr-checkmate.json');
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (fs.existsSync(configPath)) {
|
|
109
|
-
try {
|
|
110
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
111
|
-
console.error(`[loadUserConfig]: ✅ Loaded user config from: ${configPath}`);
|
|
112
|
-
return config;
|
|
113
|
-
} catch (err) {
|
|
114
|
-
console.warn(`[loadUserConfig]: ⚠️ Failed to parse ${configPath}:`, err.message);
|
|
115
|
-
}
|
|
116
|
-
} else {
|
|
117
|
-
console.error(`[loadUserConfig]: No pr-checkmate.json found, using defaults`);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return { sourcePath: 'src', eslint: {} };
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const userConfig = loadUserConfig();
|
|
124
|
-
const SRC = userConfig.sourcePath || 'src';
|
|
125
|
-
|
|
126
|
-
// Merge default rules with user-defined rules
|
|
127
|
-
const mergedRules = {
|
|
128
|
-
...defaultRules,
|
|
129
|
-
...(userConfig.eslint?.rules || {}),
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
// Merge default ignores with user-defined ignores
|
|
133
|
-
const mergedIgnores = [
|
|
134
|
-
...defaultIgnores,
|
|
135
|
-
'**/.eslintrc.js',
|
|
136
|
-
'**/eslint.config.mjs',
|
|
137
|
-
...(userConfig.eslint?.ignorePatterns || []),
|
|
138
|
-
];
|
|
139
|
-
|
|
140
|
-
// Log customization info
|
|
141
|
-
const customRulesCount = Object.keys(userConfig.eslint?.rules || {}).length;
|
|
142
|
-
const customIgnoresCount = (userConfig.eslint?.ignorePatterns || []).length;
|
|
143
|
-
|
|
144
|
-
if (customRulesCount > 0) {
|
|
145
|
-
console.error(`Applied ${customRulesCount} custom ESLint rules`);
|
|
146
|
-
}
|
|
147
|
-
if (customIgnoresCount > 0) {
|
|
148
|
-
console.error(`🚫 Applied ${customIgnoresCount} custom ignore patterns`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
console.error(`ESLint checking: ${SRC}/**/*.{ts,tsx,js,jsx}`);
|
|
152
|
-
|
|
153
|
-
export default [
|
|
154
|
-
// Global ignores must be in a separate config object
|
|
155
|
-
{
|
|
156
|
-
ignores: mergedIgnores,
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
files: [`${SRC}/**/*.{ts,tsx,js,jsx}`],
|
|
160
|
-
|
|
161
|
-
languageOptions: {
|
|
162
|
-
parser: tsParser,
|
|
163
|
-
parserOptions: {
|
|
164
|
-
ecmaVersion: 2020,
|
|
165
|
-
sourceType: 'module',
|
|
166
|
-
project: './tsconfig.json',
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
|
|
170
|
-
plugins: {
|
|
171
|
-
'@typescript-eslint': tsPlugin,
|
|
172
|
-
prettier: prettierPlugin,
|
|
173
|
-
sonarjs: sonarjsPlugin,
|
|
174
|
-
import: importPlugin,
|
|
175
|
-
jsdoc: jsdocPlugin,
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
rules: mergedRules,
|
|
179
|
-
},
|
|
180
|
-
];
|
|
File without changes
|
|
File without changes
|