pr-checkmate 1.20.4 → 1.20.7

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/.eslintrc.js CHANGED
@@ -59,6 +59,14 @@ module.exports = {
59
59
  '@typescript-eslint/explicit-function-return-type': ['warn'],
60
60
  '@typescript-eslint/no-explicit-any': ['warn'],
61
61
  '@typescript-eslint/no-floating-promises': ['error'],
62
+ '@typescript-eslint/no-unused-expressions': [
63
+ 'error',
64
+ {
65
+ allowShortCircuit: false,
66
+ allowTernary: false,
67
+ allowTaggedTemplates: false,
68
+ },
69
+ ],
62
70
  'space-before-function-paren': 'off',
63
71
  'operator-linebreak': 'off',
64
72
  'max-len': ['warn', { code: 100 }],
@@ -145,3 +145,100 @@ jobs:
145
145
  - name: Run Dependency Check
146
146
  run: npx pr-checkmate dependencies
147
147
  continue-on-error: true
148
+
149
+ circular-deps:
150
+ name: Circular Dependencies
151
+ runs-on: ubuntu-latest
152
+ steps:
153
+ - name: Checkout code
154
+ uses: actions/checkout@v4
155
+
156
+ - name: Setup Node.js
157
+ uses: actions/setup-node@v4
158
+ with:
159
+ node-version: 20
160
+
161
+ - name: Install dependencies
162
+ run: npm ci
163
+
164
+ - name: Run Circular Dependency Check
165
+ run: npx pr-checkmate circular
166
+ continue-on-error: true
167
+
168
+ license-check:
169
+ name: License Check
170
+ runs-on: ubuntu-latest
171
+ steps:
172
+ - name: Checkout code
173
+ uses: actions/checkout@v4
174
+
175
+ - name: Setup Node.js
176
+ uses: actions/setup-node@v4
177
+ with:
178
+ node-version: 20
179
+
180
+ - name: Install dependencies
181
+ run: npm ci
182
+
183
+ - name: Run License Check
184
+ run: npx pr-checkmate license
185
+ continue-on-error: true
186
+
187
+ pr-size:
188
+ name: PR Size
189
+ runs-on: ubuntu-latest
190
+ steps:
191
+ - name: Checkout code
192
+ uses: actions/checkout@v4
193
+ with:
194
+ fetch-depth: 0
195
+
196
+ - name: Setup Node.js
197
+ uses: actions/setup-node@v4
198
+ with:
199
+ node-version: 20
200
+
201
+ - name: Install dependencies
202
+ run: npm ci
203
+
204
+ - name: Check PR Size
205
+ run: npx pr-checkmate pr-size
206
+ continue-on-error: true
207
+
208
+ pr-title:
209
+ name: PR Title
210
+ runs-on: ubuntu-latest
211
+ steps:
212
+ - name: Checkout code
213
+ uses: actions/checkout@v4
214
+
215
+ - name: Setup Node.js
216
+ uses: actions/setup-node@v4
217
+ with:
218
+ node-version: 20
219
+
220
+ - name: Install dependencies
221
+ run: npm ci
222
+
223
+ - name: Check PR Title
224
+ run: npx pr-checkmate pr-title
225
+ continue-on-error: true
226
+
227
+ outdated-deps:
228
+ name: Outdated Dependencies
229
+ runs-on: ubuntu-latest
230
+ steps:
231
+ - name: Checkout code
232
+ uses: actions/checkout@v4
233
+
234
+ - name: Setup Node.js
235
+ uses: actions/setup-node@v4
236
+ with:
237
+ node-version: 20
238
+
239
+ - name: Install dependencies
240
+ run: npm ci
241
+
242
+ - name: Check Outdated Dependencies
243
+ run: npx pr-checkmate outdated
244
+ continue-on-error: true
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runNpmAudit = exports.runSecurityScan = exports.runSpellcheck = exports.runPrettier = exports.runDependencyCheck = exports.runLint = exports.hasLocalConfig = exports.getPackageConfigPath = exports.getSourcePath = void 0;
3
+ exports.runOutdatedDeps = exports.runPrTitleLint = exports.runPrSizeCheck = exports.runLicenseCheck = exports.runCircularDeps = exports.runNpmAudit = exports.runSecurityScan = exports.runSpellcheck = exports.runPrettier = exports.runDependencyCheck = exports.runLint = exports.hasLocalConfig = exports.getPackageConfigPath = exports.getSourcePath = void 0;
4
4
  exports.runAllChecks = runAllChecks;
5
5
  exports.runChecks = runChecks;
6
6
  /**
@@ -14,6 +14,12 @@ const prettier_autoformat_1 = require("./scripts/prettier-autoformat");
14
14
  const spellcheck_1 = require("./scripts/spellcheck");
15
15
  const security_1 = require("./scripts/security");
16
16
  const npm_audit_1 = require("./scripts/npm-audit");
17
+ const circular_deps_1 = require("./scripts/circular-deps");
18
+ const license_check_1 = require("./scripts/license-check");
19
+ const pr_size_check_1 = require("./scripts/pr-size-check");
20
+ const pr_title_lint_1 = require("./scripts/pr-title-lint");
21
+ const outdated_deps_1 = require("./scripts/outdated-deps");
22
+ const utils_1 = require("./utils");
17
23
  var config_1 = require("./config");
18
24
  Object.defineProperty(exports, "getSourcePath", { enumerable: true, get: function () { return config_1.getSourcePath; } });
19
25
  Object.defineProperty(exports, "getPackageConfigPath", { enumerable: true, get: function () { return config_1.getPackageConfigPath; } });
@@ -30,28 +36,66 @@ var security_2 = require("./scripts/security");
30
36
  Object.defineProperty(exports, "runSecurityScan", { enumerable: true, get: function () { return security_2.runSecurityScan; } });
31
37
  var npm_audit_2 = require("./scripts/npm-audit");
32
38
  Object.defineProperty(exports, "runNpmAudit", { enumerable: true, get: function () { return npm_audit_2.runNpmAudit; } });
39
+ var circular_deps_2 = require("./scripts/circular-deps");
40
+ Object.defineProperty(exports, "runCircularDeps", { enumerable: true, get: function () { return circular_deps_2.runCircularDeps; } });
41
+ var license_check_2 = require("./scripts/license-check");
42
+ Object.defineProperty(exports, "runLicenseCheck", { enumerable: true, get: function () { return license_check_2.runLicenseCheck; } });
43
+ var pr_size_check_2 = require("./scripts/pr-size-check");
44
+ Object.defineProperty(exports, "runPrSizeCheck", { enumerable: true, get: function () { return pr_size_check_2.runPrSizeCheck; } });
45
+ var pr_title_lint_2 = require("./scripts/pr-title-lint");
46
+ Object.defineProperty(exports, "runPrTitleLint", { enumerable: true, get: function () { return pr_title_lint_2.runPrTitleLint; } });
47
+ var outdated_deps_2 = require("./scripts/outdated-deps");
48
+ Object.defineProperty(exports, "runOutdatedDeps", { enumerable: true, get: function () { return outdated_deps_2.runOutdatedDeps; } });
33
49
  /**
34
- * Run all checks sequentially
35
- * @returns Promise that resolves when all checks complete
50
+ * Run all checks with parallel execution where possible.
51
+ * Blocking: lint, deps, npm-audit, security, circular-deps, license.
52
+ * Informational: pr-size, pr-title, outdated, spellcheck.
53
+ * Last: prettier (writes files).
36
54
  */
37
55
  async function runAllChecks() {
38
- await (0, lint_1.runLint)();
39
- await (0, dependency_check_1.runDependencyCheck)();
40
- await (0, npm_audit_1.runNpmAudit)();
41
- await (0, spellcheck_1.runSpellcheck)();
42
- await (0, security_1.runSecurityScan)();
43
- await (0, prettier_autoformat_1.runPrettier)(); // Last to commit any fixes
56
+ // Phase 1: blocking checks in parallel
57
+ await Promise.all([
58
+ (0, lint_1.runLint)(),
59
+ (0, dependency_check_1.runDependencyCheck)(),
60
+ (0, npm_audit_1.runNpmAudit)(),
61
+ (0, security_1.runSecurityScan)(),
62
+ (0, circular_deps_1.runCircularDeps)(),
63
+ (0, license_check_1.runLicenseCheck)(),
64
+ ]);
65
+ // Phase 2: informational checks in parallel
66
+ await Promise.all([
67
+ (0, pr_size_check_1.runPrSizeCheck)(),
68
+ (0, pr_title_lint_1.runPrTitleLint)(),
69
+ (0, outdated_deps_1.runOutdatedDeps)(),
70
+ (0, spellcheck_1.runSpellcheck)().catch(() => utils_1.logger.warn('⚠️ Spellcheck found issues, continuing...')),
71
+ ]);
72
+ // Phase 3: prettier last — writes files
73
+ await (0, prettier_autoformat_1.runPrettier)();
44
74
  }
45
75
  /**
46
- * Run checks based on configuration
76
+ * Run checks based on configuration (programmatic API).
47
77
  */
48
78
  async function runChecks(config = {}) {
49
79
  if (!config.skipLint)
50
80
  await (0, lint_1.runLint)();
51
81
  if (!config.skipDeps)
52
82
  await (0, dependency_check_1.runDependencyCheck)();
83
+ if (!config.skipSecurity)
84
+ await (0, security_1.runSecurityScan)();
85
+ if (!config.skipNpmAudit)
86
+ await (0, npm_audit_1.runNpmAudit)();
87
+ if (!config.skipCircularDeps)
88
+ await (0, circular_deps_1.runCircularDeps)();
89
+ if (!config.skipLicense)
90
+ await (0, license_check_1.runLicenseCheck)();
91
+ if (!config.skipPrSize)
92
+ await (0, pr_size_check_1.runPrSizeCheck)();
93
+ if (!config.skipPrTitle)
94
+ await (0, pr_title_lint_1.runPrTitleLint)();
95
+ if (!config.skipOutdated)
96
+ await (0, outdated_deps_1.runOutdatedDeps)();
53
97
  if (!config.skipSpell)
54
98
  await (0, spellcheck_1.runSpellcheck)();
55
- if (!config.skipFormat && config.autoCommit)
99
+ if (!config.skipFormat)
56
100
  await (0, prettier_autoformat_1.runPrettier)();
57
101
  }
package/dist/init.js CHANGED
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
@@ -49,6 +48,7 @@ async function init() {
49
48
  type: 'input',
50
49
  name: 'manualPath',
51
50
  message: 'Enter path:',
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
52
  when: (a) => a.sourcePath === 'Enter manually',
53
53
  validate: (input) => input.trim().length > 0 || 'Cannot be empty',
54
54
  },
@@ -0,0 +1,34 @@
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.runCircularDeps = runCircularDeps;
7
+ const execa_1 = require("execa");
8
+ const utils_1 = require("../utils");
9
+ const config_1 = require("../config");
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ async function runCircularDeps() {
12
+ utils_1.logger.info('[runCircularDeps]: 🔄 Checking for circular dependencies...');
13
+ const sourcePath = (0, config_1.getSourcePath)();
14
+ const pattern = node_path_1.default.join(process.cwd(), sourcePath, '**/*.{ts,tsx,js,jsx}');
15
+ try {
16
+ const result = await (0, execa_1.execa)('npx', ['dpdm', '--no-warning', '--no-tree', '--circular', pattern], {
17
+ reject: false,
18
+ });
19
+ const output = (result.stdout + result.stderr).trim();
20
+ if (output.toLowerCase().includes('circular')) {
21
+ utils_1.logger.error('[runCircularDeps]: ❌ Circular dependencies detected:');
22
+ utils_1.logger.error(output);
23
+ throw new Error('Circular dependencies found');
24
+ }
25
+ utils_1.logger.info('[runCircularDeps]: ✅ No circular dependencies found');
26
+ }
27
+ catch (err) {
28
+ const error = err;
29
+ if (error.message === 'Circular dependencies found')
30
+ throw err;
31
+ utils_1.logger.error(`[runCircularDeps]: ❌ Circular dep check failed\n${err}`);
32
+ throw err;
33
+ }
34
+ }
@@ -4,33 +4,42 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runDependencyCheck = runDependencyCheck;
7
- const config_1 = require("../config");
7
+ const execa_1 = require("execa");
8
8
  const utils_1 = require("../utils");
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
10
  const node_fs_1 = __importDefault(require("node:fs"));
11
- /**
12
- * Basic dependency checks with sourcePath support
13
- */
14
11
  async function runDependencyCheck() {
15
- utils_1.logger.info('📦 Checking dependencies...');
12
+ utils_1.logger.info('[runDependencyCheck]: 📦 Checking dependencies...');
16
13
  const projectRoot = process.cwd();
17
- const packageJsonPath = node_path_1.default.join(projectRoot, 'package.json');
18
- if (!node_fs_1.default.existsSync(packageJsonPath)) {
19
- utils_1.logger.warn('[runDependencyCheck]: ⚠️ No package.json — skipping dependency check');
14
+ if (!node_fs_1.default.existsSync(node_path_1.default.join(projectRoot, 'package.json'))) {
15
+ utils_1.logger.warn('[runDependencyCheck]: ⚠️ No package.json found, skipping');
20
16
  return;
21
17
  }
22
- const sourcePath = (0, config_1.getSourcePath)();
23
- const sourceFolder = node_path_1.default.join(projectRoot, sourcePath);
24
- if (!node_fs_1.default.existsSync(sourceFolder)) {
25
- utils_1.logger.warn(`[runDependencyCheck]: ⚠️ Source folder "${sourcePath}" not found — skipping deeper checks`);
26
- return;
18
+ try {
19
+ const { stdout } = await (0, execa_1.execa)('npx', ['depcheck', '--json'], { cwd: projectRoot });
20
+ const result = JSON.parse(stdout);
21
+ const unused = result.dependencies ?? [];
22
+ const missing = Object.keys(result.missing ?? {});
23
+ if (unused.length === 0 && missing.length === 0) {
24
+ utils_1.logger.info('[runDependencyCheck]: ✅ Dependencies are clean');
25
+ return;
26
+ }
27
+ if (unused.length > 0) {
28
+ utils_1.logger.warn(`[runDependencyCheck]: ⚠️ ${unused.length} unused dependency(ies):`);
29
+ unused.forEach(dep => utils_1.logger.warn(` ${dep}`));
30
+ }
31
+ if (missing.length > 0) {
32
+ utils_1.logger.error(`[runDependencyCheck]: ❌ ${missing.length} missing dependency(ies):`);
33
+ missing.forEach(dep => utils_1.logger.error(` ${dep} (used in: ${result.missing[dep]?.join(', ')})`));
34
+ throw new Error(`Missing dependencies: ${missing.join(', ')}`);
35
+ }
36
+ // Unused deps are warnings — don't block the build
27
37
  }
28
- const ignored = config_1.IGNORE_PATTERNS.some(pattern => {
29
- const clean = pattern.replace(/\*\*/g, '').replace(/\//g, '').trim();
30
- return clean && sourceFolder.includes(clean);
31
- });
32
- if (ignored) {
33
- utils_1.logger.warn('[runDependencyCheck]: ⚠️ Source path contains ignored directories');
38
+ catch (err) {
39
+ const error = err;
40
+ if (error.message?.startsWith('Missing dependencies'))
41
+ throw err;
42
+ utils_1.logger.error(`[runDependencyCheck]: ❌ Dependency check failed\n${err}`);
43
+ throw err;
34
44
  }
35
- utils_1.logger.info('[runDependencyCheck]: ✅ Dependencies OK');
36
45
  }
@@ -20,6 +20,11 @@ const prettier_autoformat_1 = require("./prettier-autoformat");
20
20
  const spellcheck_1 = require("./spellcheck");
21
21
  const security_1 = require("./security");
22
22
  const npm_audit_1 = require("./npm-audit");
23
+ const circular_deps_1 = require("./circular-deps");
24
+ const license_check_1 = require("./license-check");
25
+ const pr_size_check_1 = require("./pr-size-check");
26
+ const pr_title_lint_1 = require("./pr-title-lint");
27
+ const outdated_deps_1 = require("./outdated-deps");
23
28
  const utils_1 = require("../utils");
24
29
  const lint_1 = require("./lint");
25
30
  __exportStar(require("./dependency-check"), exports);
@@ -27,32 +32,45 @@ __exportStar(require("./lint"), exports);
27
32
  __exportStar(require("./prettier-autoformat"), exports);
28
33
  __exportStar(require("./spellcheck"), exports);
29
34
  __exportStar(require("./security"), exports);
35
+ __exportStar(require("./circular-deps"), exports);
36
+ __exportStar(require("./license-check"), exports);
37
+ __exportStar(require("./pr-size-check"), exports);
38
+ __exportStar(require("./pr-title-lint"), exports);
39
+ __exportStar(require("./outdated-deps"), exports);
30
40
  async function runJob(jobName) {
31
41
  utils_1.logger.info(`[runJob]: 🚀 Running job: ${jobName}`);
32
42
  try {
33
43
  switch (jobName) {
34
44
  case 'all':
35
- await (0, lint_1.runLint)();
36
- await (0, dependency_check_1.runDependencyCheck)();
37
- await (0, security_1.runSecurityScan)();
38
- await (0, npm_audit_1.runNpmAudit)();
45
+ // Phase 1: blocking checks in parallel
46
+ await Promise.all([
47
+ (0, lint_1.runLint)(),
48
+ (0, dependency_check_1.runDependencyCheck)(),
49
+ (0, npm_audit_1.runNpmAudit)(),
50
+ (0, security_1.runSecurityScan)(),
51
+ (0, circular_deps_1.runCircularDeps)(),
52
+ (0, license_check_1.runLicenseCheck)(),
53
+ ]);
54
+ // Phase 2: informational checks in parallel (never block)
55
+ await Promise.all([
56
+ (0, pr_size_check_1.runPrSizeCheck)(),
57
+ (0, pr_title_lint_1.runPrTitleLint)(),
58
+ (0, outdated_deps_1.runOutdatedDeps)(),
59
+ (0, spellcheck_1.runSpellcheck)().catch(() => utils_1.logger.warn('⚠️ Spellcheck found issues, continuing...')),
60
+ ]);
61
+ // Phase 3: prettier last — writes files
39
62
  try {
40
63
  await (0, prettier_autoformat_1.runPrettier)();
41
64
  }
42
65
  catch {
43
66
  utils_1.logger.warn('⚠️ Prettier failed, continuing...');
44
67
  }
45
- try {
46
- await (0, spellcheck_1.runSpellcheck)();
47
- }
48
- catch {
49
- utils_1.logger.warn('⚠️ Spellcheck failed, continuing...');
50
- }
51
68
  break;
52
69
  case 'lint':
53
70
  await (0, lint_1.runLint)();
54
71
  break;
55
72
  case 'deps':
73
+ case 'dependencies':
56
74
  await (0, dependency_check_1.runDependencyCheck)();
57
75
  break;
58
76
  case 'npm-audit':
@@ -67,8 +85,23 @@ async function runJob(jobName) {
67
85
  case 'security':
68
86
  await (0, security_1.runSecurityScan)();
69
87
  break;
88
+ case 'circular':
89
+ await (0, circular_deps_1.runCircularDeps)();
90
+ break;
91
+ case 'license':
92
+ await (0, license_check_1.runLicenseCheck)();
93
+ break;
94
+ case 'pr-size':
95
+ await (0, pr_size_check_1.runPrSizeCheck)();
96
+ break;
97
+ case 'pr-title':
98
+ await (0, pr_title_lint_1.runPrTitleLint)();
99
+ break;
100
+ case 'outdated':
101
+ await (0, outdated_deps_1.runOutdatedDeps)();
102
+ break;
70
103
  default:
71
- utils_1.logger.warn(`[runJob]: Unknown job "${jobName}". Available: all, lint, deps, prettier, spellcheck`);
104
+ utils_1.logger.warn(`[runJob]: Unknown job "${jobName}". Available: all, lint, deps, npm-audit, prettier, spellcheck, security, circular, license, pr-size, pr-title, outdated`);
72
105
  }
73
106
  }
74
107
  catch (err) {
@@ -0,0 +1,44 @@
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.runLicenseCheck = runLicenseCheck;
7
+ const execa_1 = require("execa");
8
+ const utils_1 = require("../utils");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const node_fs_1 = __importDefault(require("node:fs"));
11
+ const FORBIDDEN_LICENSES = ['GPL-2.0', 'GPL-3.0', 'AGPL-3.0', 'LGPL-2.0', 'LGPL-2.1', 'LGPL-3.0'];
12
+ async function runLicenseCheck() {
13
+ utils_1.logger.info('[runLicenseCheck]: 📄 Checking dependency licenses...');
14
+ if (!node_fs_1.default.existsSync(node_path_1.default.join(process.cwd(), 'package.json'))) {
15
+ utils_1.logger.warn('[runLicenseCheck]: ⚠️ No package.json found, skipping');
16
+ return;
17
+ }
18
+ try {
19
+ const { stdout } = await (0, execa_1.execa)('npx', ['license-checker', '--json', '--production'], {
20
+ cwd: process.cwd(),
21
+ });
22
+ const licenses = JSON.parse(stdout);
23
+ const violations = [];
24
+ for (const [pkg, info] of Object.entries(licenses)) {
25
+ const license = info.licenses ?? '';
26
+ if (FORBIDDEN_LICENSES.some(f => license.includes(f))) {
27
+ violations.push(` ${pkg}: ${license}`);
28
+ }
29
+ }
30
+ if (violations.length > 0) {
31
+ utils_1.logger.error(`[runLicenseCheck]: ❌ ${violations.length} forbidden license(s) found:`);
32
+ violations.forEach(v => utils_1.logger.error(v));
33
+ throw new Error(`License violations: ${violations.length}`);
34
+ }
35
+ utils_1.logger.info('[runLicenseCheck]: ✅ All licenses are compliant');
36
+ }
37
+ catch (err) {
38
+ const error = err;
39
+ if (error.message?.startsWith('License violations'))
40
+ throw err;
41
+ utils_1.logger.error(`[runLicenseCheck]: ❌ License check failed\n${err}`);
42
+ throw err;
43
+ }
44
+ }
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runLint = runLint;
7
7
  const config_1 = require("../config");
8
8
  const utils_1 = require("../utils");
9
+ const delta_1 = require("../utils/delta");
9
10
  const execa_1 = require("execa");
10
11
  const node_path_1 = __importDefault(require("node:path"));
11
12
  /**
@@ -26,6 +27,8 @@ async function runLint() {
26
27
  const projectRoot = process.cwd();
27
28
  const sourcePath = (0, config_1.getSourcePath)();
28
29
  const sourceFullPath = node_path_1.default.join(projectRoot, sourcePath);
30
+ const changedFiles = await (0, delta_1.getChangedFiles)(['.ts', '.tsx', '.js', '.jsx']);
31
+ const targets = changedFiles ?? [sourceFullPath];
29
32
  const hasLocal = (0, config_1.hasLocalConfig)([
30
33
  'eslint.config.mjs',
31
34
  'eslint.config.js',
@@ -36,24 +39,16 @@ async function runLint() {
36
39
  let args;
37
40
  if (hasLocal) {
38
41
  utils_1.logger.info(`[runLint]: 📋 Using local ESLint config (checking: ${sourcePath})`);
39
- args = ['eslint', sourceFullPath, '--ext', '.ts,.tsx,.js,.jsx', '--fix'];
42
+ args = ['eslint', ...targets, '--ext', '.ts,.tsx,.js,.jsx', '--fix'];
40
43
  }
41
44
  else {
42
- utils_1.logger.info(`📦 Using pr-checkmate ESLint config (checking: ${sourcePath})`);
45
+ utils_1.logger.info(`[runLint]: 📦 Using pr-checkmate ESLint config (checking: ${sourcePath})`);
43
46
  // Detect ESLint version and choose appropriate config
44
47
  const eslintVersion = await getESLintMajorVersion();
45
48
  const configFile = eslintVersion >= 9 ? 'eslint.config.mjs' : '.eslintrc.js';
46
49
  const configPath = (0, config_1.getPackageConfigPath)(configFile);
47
50
  utils_1.logger.info(`[runLint]: 📋 Detected ESLint v${eslintVersion}, using ${configFile}`);
48
- args = [
49
- 'eslint',
50
- sourceFullPath,
51
- '--ext',
52
- '.ts,.tsx,.js,.jsx',
53
- '--fix',
54
- '--config',
55
- configPath,
56
- ];
51
+ args = ['eslint', ...targets, '--ext', '.ts,.tsx,.js,.jsx', '--fix', '--config', configPath];
57
52
  }
58
53
  config_1.IGNORE_PATTERNS.forEach(p => args.push('--ignore-pattern', p));
59
54
  try {
@@ -7,9 +7,7 @@ exports.runNpmAudit = runNpmAudit;
7
7
  const utils_1 = require("../utils");
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const node_fs_1 = __importDefault(require("node:fs"));
10
- const node_child_process_1 = require("node:child_process");
11
- const node_util_1 = require("node:util");
12
- const execAsync = (0, node_util_1.promisify)(node_child_process_1.exec);
10
+ const execa_1 = require("execa");
13
11
  /**
14
12
  * Run npm audit on the current project
15
13
  */
@@ -22,15 +20,13 @@ async function runNpmAudit() {
22
20
  return;
23
21
  }
24
22
  try {
25
- const { stdout, stderr } = await execAsync('npm audit --audit-level=moderate', {
23
+ const { stdout, stderr } = await (0, execa_1.execa)('npm', ['audit', '--audit-level=moderate'], {
26
24
  cwd: projectRoot,
27
25
  });
28
- if (stdout) {
26
+ if (stdout)
29
27
  utils_1.logger.info(stdout);
30
- }
31
- if (stderr) {
28
+ if (stderr)
32
29
  utils_1.logger.warn(stderr);
33
- }
34
30
  utils_1.logger.info('[runNpmAudit]: ✅ NPM audit finished successfully');
35
31
  }
36
32
  catch (error) {
@@ -42,5 +38,6 @@ async function runNpmAudit() {
42
38
  utils_1.logger.warn(err.stderr);
43
39
  if (!err.stdout && !err.stderr)
44
40
  utils_1.logger.error(err.message);
41
+ throw err;
45
42
  }
46
43
  }
@@ -0,0 +1,52 @@
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.runOutdatedDeps = runOutdatedDeps;
7
+ const execa_1 = require("execa");
8
+ const utils_1 = require("../utils");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const node_fs_1 = __importDefault(require("node:fs"));
11
+ async function runOutdatedDeps() {
12
+ utils_1.logger.info('[runOutdatedDeps]: 📅 Checking for outdated dependencies...');
13
+ if (!node_fs_1.default.existsSync(node_path_1.default.join(process.cwd(), 'package.json'))) {
14
+ utils_1.logger.warn('[runOutdatedDeps]: ⚠️ No package.json found, skipping');
15
+ return;
16
+ }
17
+ // npm outdated exits with code 1 when outdated packages exist — use reject:false
18
+ const result = await (0, execa_1.execa)('npm', ['outdated', '--json'], { reject: false });
19
+ if (!result.stdout?.trim()) {
20
+ utils_1.logger.info('[runOutdatedDeps]: ✅ All dependencies are up to date');
21
+ return;
22
+ }
23
+ let outdated;
24
+ try {
25
+ outdated = JSON.parse(result.stdout);
26
+ }
27
+ catch {
28
+ utils_1.logger.info('[runOutdatedDeps]: ✅ All dependencies are up to date');
29
+ return;
30
+ }
31
+ const entries = Object.entries(outdated);
32
+ if (entries.length === 0) {
33
+ utils_1.logger.info('[runOutdatedDeps]: ✅ All dependencies are up to date');
34
+ return;
35
+ }
36
+ const majorBehind = entries.filter(([, info]) => {
37
+ const current = parseInt(info.current?.split('.')[0] ?? '0');
38
+ const latest = parseInt(info.latest?.split('.')[0] ?? '0');
39
+ return latest > current;
40
+ });
41
+ const minorBehind = entries.length - majorBehind.length;
42
+ if (majorBehind.length > 0) {
43
+ utils_1.logger.warn(`[runOutdatedDeps]: ⚠️ ${majorBehind.length} package(s) are major versions behind:`);
44
+ majorBehind.forEach(([pkg, info]) => {
45
+ utils_1.logger.warn(` ${pkg}: ${info.current} → ${info.latest}`);
46
+ });
47
+ }
48
+ if (minorBehind > 0) {
49
+ utils_1.logger.info(`[runOutdatedDeps]: ℹ️ ${minorBehind} package(s) have minor/patch updates available`);
50
+ }
51
+ // informational only — never throws
52
+ }
@@ -0,0 +1,56 @@
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.runPrSizeCheck = runPrSizeCheck;
7
+ const execa_1 = require("execa");
8
+ const utils_1 = require("../utils");
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const WARN_FILES = 50;
11
+ const WARN_LINES = 1000;
12
+ function readBaseSha() {
13
+ const eventName = process.env.GITHUB_EVENT_NAME;
14
+ const eventPath = process.env.GITHUB_EVENT_PATH;
15
+ if (eventName !== 'pull_request' || !eventPath || !node_fs_1.default.existsSync(eventPath)) {
16
+ return null;
17
+ }
18
+ try {
19
+ const event = JSON.parse(node_fs_1.default.readFileSync(eventPath, 'utf-8'));
20
+ return event?.pull_request?.base?.sha ?? null;
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ async function runPrSizeCheck() {
27
+ utils_1.logger.info('[runPrSizeCheck]: 📏 Checking PR size...');
28
+ const baseSha = readBaseSha();
29
+ if (!baseSha) {
30
+ utils_1.logger.info('[runPrSizeCheck]: ℹ️ Not in GitHub PR context, skipping');
31
+ return;
32
+ }
33
+ try {
34
+ const { stdout } = await (0, execa_1.execa)('git', ['diff', '--shortstat', baseSha, 'HEAD']);
35
+ // "5 files changed, 123 insertions(+), 45 deletions(-)"
36
+ const filesMatch = stdout.match(/(\d+) files? changed/);
37
+ const insertions = stdout.match(/(\d+) insertion/);
38
+ const deletions = stdout.match(/(\d+) deletion/);
39
+ const fileCount = filesMatch ? parseInt(filesMatch[1]) : 0;
40
+ const lines = (insertions ? parseInt(insertions[1]) : 0) + (deletions ? parseInt(deletions[1]) : 0);
41
+ utils_1.logger.info(`[runPrSizeCheck]: 📊 ${fileCount} files changed, ${lines} lines`);
42
+ if (fileCount > WARN_FILES) {
43
+ utils_1.logger.warn(`[runPrSizeCheck]: ⚠️ Large PR: ${fileCount} files changed (recommended < ${WARN_FILES})`);
44
+ }
45
+ if (lines > WARN_LINES) {
46
+ utils_1.logger.warn(`[runPrSizeCheck]: ⚠️ Large PR: ${lines} lines changed (recommended < ${WARN_LINES})`);
47
+ }
48
+ if (fileCount <= WARN_FILES && lines <= WARN_LINES) {
49
+ utils_1.logger.info('[runPrSizeCheck]: ✅ PR size is within limits');
50
+ }
51
+ }
52
+ catch (err) {
53
+ utils_1.logger.warn(`[runPrSizeCheck]: ⚠️ Could not measure PR size\n${err}`);
54
+ // informational — never block
55
+ }
56
+ }
@@ -0,0 +1,40 @@
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.runPrTitleLint = runPrTitleLint;
7
+ const utils_1 = require("../utils");
8
+ const node_fs_1 = __importDefault(require("node:fs"));
9
+ const CONVENTIONAL_PREFIX = /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?!?: .+/;
10
+ async function runPrTitleLint() {
11
+ utils_1.logger.info('[runPrTitleLint]: 📝 Checking PR title...');
12
+ const eventPath = process.env.GITHUB_EVENT_PATH;
13
+ if (!eventPath || !node_fs_1.default.existsSync(eventPath)) {
14
+ utils_1.logger.info('[runPrTitleLint]: ℹ️ Not in GitHub CI, skipping');
15
+ return;
16
+ }
17
+ let event;
18
+ try {
19
+ event = JSON.parse(node_fs_1.default.readFileSync(eventPath, 'utf-8'));
20
+ }
21
+ catch (err) {
22
+ utils_1.logger.warn(`[runPrTitleLint]: ⚠️ Could not read GitHub event\n${err}`);
23
+ return;
24
+ }
25
+ const pr = event.pull_request;
26
+ if (!pr?.title) {
27
+ utils_1.logger.info('[runPrTitleLint]: ℹ️ No PR title found, skipping');
28
+ return;
29
+ }
30
+ const title = pr.title;
31
+ if (!CONVENTIONAL_PREFIX.test(title)) {
32
+ utils_1.logger.warn(`[runPrTitleLint]: ⚠️ PR title doesn't follow Conventional Commits`);
33
+ utils_1.logger.warn(` Got: "${title}"`);
34
+ utils_1.logger.warn(` Expected: type(scope): description`);
35
+ utils_1.logger.warn(` Types: feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert`);
36
+ // warning only — teams may not use Conventional Commits
37
+ return;
38
+ }
39
+ utils_1.logger.info(`[runPrTitleLint]: ✅ PR title is valid: "${title}"`);
40
+ }
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runPrettier = runPrettier;
7
7
  const config_1 = require("../config");
8
8
  const utils_1 = require("../utils");
9
+ const delta_1 = require("../utils/delta");
9
10
  const execa_1 = require("execa");
10
11
  const node_path_1 = __importDefault(require("node:path"));
11
12
  const node_fs_1 = __importDefault(require("node:fs"));
@@ -58,24 +59,12 @@ function createTempIgnoreFile() {
58
59
  node_fs_1.default.writeFileSync(file, config_1.IGNORE_PATTERNS.join('\n'), 'utf-8');
59
60
  return file;
60
61
  }
61
- /**
62
- * Remove temporary file
63
- */
64
- function cleanupTempFile(filePath) {
65
- try {
66
- if (node_fs_1.default.existsSync(filePath)) {
67
- node_fs_1.default.unlinkSync(filePath);
68
- }
69
- }
70
- catch (err) {
71
- utils_1.logger.warn(`[cleanupTempFile]: ⚠️ Failed cleanup: ${filePath}\n${err}`);
72
- }
73
- }
74
62
  async function runPrettier() {
75
63
  utils_1.logger.info('[runPrettier]: 🎨 Running Prettier...');
76
64
  const root = process.cwd();
77
65
  const sourcePath = (0, config_1.getSourcePath)();
78
- const targetGlob = `${node_path_1.default.join(root, sourcePath)}/**/*.{ts,tsx,js,jsx,json,md}`;
66
+ const changedFiles = await (0, delta_1.getChangedFiles)(['.ts', '.tsx', '.js', '.jsx', '.json', '.md']);
67
+ const targets = changedFiles ?? [`${node_path_1.default.join(root, sourcePath)}/**/*.{ts,tsx,js,jsx,json,md}`];
79
68
  const projectIgnore = node_path_1.default.join(root, '.prettierignore');
80
69
  const gitignore = node_path_1.default.join(root, '.gitignore');
81
70
  let ignorePath;
@@ -100,13 +89,13 @@ async function runPrettier() {
100
89
  let tempConfig = null;
101
90
  if (hasLocal) {
102
91
  utils_1.logger.info(`[runPrettier]: 📋 Using local Prettier config (checking: ${sourcePath})`);
103
- args = ['prettier', '--write', targetGlob, '--ignore-path', ignorePath];
92
+ args = ['prettier', '--write', ...targets, '--ignore-path', ignorePath];
104
93
  }
105
94
  else {
106
95
  utils_1.logger.info(`[runPrettier]: 📦 Using pr-checkmate Prettier config (checking: ${sourcePath})`);
107
96
  // Create temporary config with merged settings
108
97
  tempConfig = createTempPrettierConfig();
109
- args = ['prettier', '--write', targetGlob, '--config', tempConfig, '--ignore-path', ignorePath];
98
+ args = ['prettier', '--write', ...targets, '--config', tempConfig, '--ignore-path', ignorePath];
110
99
  }
111
100
  try {
112
101
  await (0, execa_1.execa)('npx', args, { stdio: 'inherit' });
@@ -119,8 +108,8 @@ async function runPrettier() {
119
108
  finally {
120
109
  // Cleanup temporary files
121
110
  if (tempIgnore)
122
- cleanupTempFile(tempIgnore);
111
+ (0, utils_1.cleanupTempFile)(tempIgnore);
123
112
  if (tempConfig)
124
- cleanupTempFile(tempConfig);
113
+ (0, utils_1.cleanupTempFile)(tempConfig);
125
114
  }
126
115
  }
@@ -6,15 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runSecurityScan = runSecurityScan;
7
7
  const execa_1 = require("execa");
8
8
  const utils_1 = require("../utils");
9
- const node_fs_1 = require("node:fs");
10
- const node_child_process_1 = require("node:child_process");
9
+ const node_fs_1 = __importDefault(require("node:fs"));
11
10
  const node_path_1 = __importDefault(require("node:path"));
12
11
  /**
13
12
  * Get HEAD SHA from git
14
13
  */
15
- function getHeadSha() {
14
+ async function getHeadSha() {
16
15
  try {
17
- return (0, node_child_process_1.execSync)('git rev-parse HEAD', { encoding: 'utf-8' }).trim();
16
+ const { stdout } = await (0, execa_1.execa)('git', ['rev-parse', 'HEAD']);
17
+ return stdout.trim();
18
18
  }
19
19
  catch (err) {
20
20
  utils_1.logger.warn(`⚠️ Could not determine HEAD SHA from git\n${err}`);
@@ -24,14 +24,12 @@ function getHeadSha() {
24
24
  /**
25
25
  * Get BASE SHA (for PR) or parent commit (for push)
26
26
  */
27
- function getBaseSha() {
27
+ async function getBaseSha() {
28
28
  const eventName = process.env.GITHUB_EVENT_NAME;
29
29
  const eventPath = process.env.GITHUB_EVENT_PATH;
30
30
  try {
31
- if (eventName === 'pull_request' && eventPath && (0, node_fs_1.existsSync)(eventPath)) {
32
- // For PR: use pull_request.base.sha from GitHub event
33
- const fs = require('node:fs');
34
- const event = JSON.parse(fs.readFileSync(eventPath, 'utf-8'));
31
+ if (eventName === 'pull_request' && eventPath && node_fs_1.default.existsSync(eventPath)) {
32
+ const event = JSON.parse(node_fs_1.default.readFileSync(eventPath, 'utf-8'));
35
33
  const baseSha = event?.pull_request?.base?.sha;
36
34
  if (baseSha) {
37
35
  utils_1.logger.info(`[getBaseSha]: ℹ️ Using PR base SHA: ${baseSha}`);
@@ -40,12 +38,11 @@ function getBaseSha() {
40
38
  }
41
39
  }
42
40
  catch (err) {
43
- utils_1.logger.warn(`[getBaseSha]: ⚠️ Could not read GitHub event, trying git parent commit
44
- ${err}`);
41
+ utils_1.logger.warn(`[getBaseSha]: ⚠️ Could not read GitHub event, trying git parent commit\n${err}`);
45
42
  }
46
- // For push: use parent commit
47
43
  try {
48
- return (0, node_child_process_1.execSync)('git rev-parse HEAD^', { encoding: 'utf-8' }).trim();
44
+ const { stdout } = await (0, execa_1.execa)('git', ['rev-parse', 'HEAD^']);
45
+ return stdout.trim();
49
46
  }
50
47
  catch (err) {
51
48
  utils_1.logger.warn(`⚠️ Could not determine BASE SHA (might be first commit)\n${err}`);
@@ -57,7 +54,7 @@ function getBaseSha() {
57
54
  */
58
55
  function getGitleaksCommand() {
59
56
  const localPath = node_path_1.default.join(process.cwd(), 'node_modules', '.bin', 'gitleaks-secret-scanner');
60
- if ((0, node_fs_1.existsSync)(localPath)) {
57
+ if (node_fs_1.default.existsSync(localPath)) {
61
58
  utils_1.logger.info('[getGitleaksCommand]: 📦 Using local gitleaks-secret-scanner');
62
59
  return localPath;
63
60
  }
@@ -70,22 +67,19 @@ function getGitleaksCommand() {
70
67
  async function runSecurityScan() {
71
68
  utils_1.logger.info('🔐 Running security scan with gitleaks-secret-scanner...');
72
69
  try {
73
- // Set up environment variables
74
- const headSha = getHeadSha();
70
+ const headSha = await getHeadSha();
75
71
  if (!headSha) {
76
72
  utils_1.logger.warn('⚠️ Could not determine HEAD SHA, security scan may not work properly');
77
73
  }
78
- const baseSha = getBaseSha();
74
+ const baseSha = await getBaseSha();
79
75
  if (!baseSha) {
80
76
  utils_1.logger.warn('⚠️ Could not determine BASE SHA, will scan all commits');
81
77
  }
82
- // Prepare environment
83
78
  const env = {
84
79
  ...process.env,
85
80
  ...(headSha && { HEAD_SHA: headSha }),
86
81
  ...(baseSha && { BASE_SHA: baseSha }),
87
82
  };
88
- // Get gitleaks command
89
83
  const cmd = getGitleaksCommand();
90
84
  const args = cmd === 'npx' ? ['gitleaks-secret-scanner', '--diff-mode', 'ci'] : ['--diff-mode', 'ci'];
91
85
  utils_1.logger.info(`Running: ${cmd} ${args.join(' ')}`);
@@ -97,12 +91,10 @@ async function runSecurityScan() {
97
91
  utils_1.logger.info('✅ Security scan completed successfully');
98
92
  }
99
93
  catch (err) {
100
- // gitleaks returns exit code 1 if secrets are found
101
- // This is expected behavior, we should inform but not necessarily crash
102
94
  if (err instanceof Error && 'exitCode' in err && err.exitCode === 1) {
103
95
  utils_1.logger.warn('⚠️ gitleaks found potential secrets - please review gitleaks-report.html');
104
96
  utils_1.logger.warn('💡 If this is a false positive, add it to .gitleaksignore');
105
- throw err; // Still throw to fail the CI
97
+ throw err;
106
98
  }
107
99
  utils_1.logger.error('[runSecurityScan]: ❌ Security scan failed');
108
100
  throw err;
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runSpellcheck = runSpellcheck;
7
7
  const config_1 = require("../config");
8
8
  const utils_1 = require("../utils");
9
+ const delta_1 = require("../utils/delta");
9
10
  const execa_1 = require("execa");
10
11
  const node_path_1 = __importDefault(require("node:path"));
11
12
  const node_fs_1 = __importDefault(require("node:fs"));
@@ -55,19 +56,6 @@ function createTempCspellConfig() {
55
56
  node_fs_1.default.writeFileSync(tempConfigPath, JSON.stringify(mergedConfig, null, 2));
56
57
  return tempConfigPath;
57
58
  }
58
- /**
59
- * Clean up temporary config file
60
- */
61
- function cleanupTempConfig(configPath) {
62
- try {
63
- if (node_fs_1.default.existsSync(configPath)) {
64
- node_fs_1.default.unlinkSync(configPath);
65
- }
66
- }
67
- catch (err) {
68
- utils_1.logger.warn(`⚠️ Failed to cleanup temp config: ${err}`);
69
- }
70
- }
71
59
  /**
72
60
  * Build cspell patterns + ignore patterns
73
61
  */
@@ -80,7 +68,16 @@ async function runSpellcheck() {
80
68
  utils_1.logger.info('[runSpellcheck]: 🔤 Running Spellcheck...');
81
69
  const projectRoot = process.cwd();
82
70
  const sourcePath = (0, config_1.getSourcePath)();
83
- const patterns = buildSpellcheckPatterns(projectRoot, sourcePath);
71
+ const changedFiles = await (0, delta_1.getChangedFiles)([
72
+ '.ts',
73
+ '.tsx',
74
+ '.js',
75
+ '.jsx',
76
+ '.md',
77
+ '.mdx',
78
+ '.json',
79
+ ]);
80
+ const patterns = changedFiles ?? buildSpellcheckPatterns(projectRoot, sourcePath);
84
81
  const hasLocal = (0, config_1.hasLocalConfig)(['cspell.json', '.cspell.json', 'cspell.config.json']);
85
82
  let args;
86
83
  let tempConfigPath = null;
@@ -105,7 +102,7 @@ async function runSpellcheck() {
105
102
  finally {
106
103
  // Cleanup temporary config
107
104
  if (tempConfigPath) {
108
- cleanupTempConfig(tempConfigPath);
105
+ (0, utils_1.cleanupTempFile)(tempConfigPath);
109
106
  }
110
107
  }
111
108
  }
@@ -0,0 +1,53 @@
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 execa_1 = require("execa");
8
+ const logger_1 = require("./logger");
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const node_path_1 = __importDefault(require("node:path"));
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
+ }
@@ -13,5 +13,22 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
13
13
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
16
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.cleanupTempFile = cleanupTempFile;
21
+ const node_fs_1 = __importDefault(require("node:fs"));
22
+ const logger_1 = require("./logger");
17
23
  __exportStar(require("./logger"), exports);
24
+ __exportStar(require("./delta"), exports);
25
+ function cleanupTempFile(filePath) {
26
+ try {
27
+ if (node_fs_1.default.existsSync(filePath)) {
28
+ node_fs_1.default.unlinkSync(filePath);
29
+ }
30
+ }
31
+ catch (err) {
32
+ logger_1.logger.warn(`[cleanupTempFile]: ⚠️ Failed cleanup: ${filePath}\n${err}`);
33
+ }
34
+ }
@@ -58,6 +58,9 @@ class Logger {
58
58
  getLogs() {
59
59
  return this.logs;
60
60
  }
61
+ setLevel(level) {
62
+ this.currentLevel = level;
63
+ }
61
64
  clear() {
62
65
  this.logs = [];
63
66
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pr-checkmate",
3
- "version": "1.20.4",
3
+ "version": "1.20.7",
4
4
  "description": "Automated PR quality checks: linting, formatting, dependency analysis, and spellcheck",
5
5
  "keywords": [
6
6
  "github-actions",
@@ -59,6 +59,14 @@ module.exports = {
59
59
  '@typescript-eslint/explicit-function-return-type': ['warn'],
60
60
  '@typescript-eslint/no-explicit-any': ['warn'],
61
61
  '@typescript-eslint/no-floating-promises': ['error'],
62
+ '@typescript-eslint/no-unused-expressions': [
63
+ 'error',
64
+ {
65
+ allowShortCircuit: false,
66
+ allowTernary: false,
67
+ allowTaggedTemplates: false,
68
+ },
69
+ ],
62
70
  'space-before-function-paren': 'off',
63
71
  'operator-linebreak': 'off',
64
72
  'max-len': ['warn', { code: 100 }],
@@ -145,3 +145,100 @@ jobs:
145
145
  - name: Run Dependency Check
146
146
  run: npx pr-checkmate dependencies
147
147
  continue-on-error: true
148
+
149
+ circular-deps:
150
+ name: Circular Dependencies
151
+ runs-on: ubuntu-latest
152
+ steps:
153
+ - name: Checkout code
154
+ uses: actions/checkout@v4
155
+
156
+ - name: Setup Node.js
157
+ uses: actions/setup-node@v4
158
+ with:
159
+ node-version: 20
160
+
161
+ - name: Install dependencies
162
+ run: npm ci
163
+
164
+ - name: Run Circular Dependency Check
165
+ run: npx pr-checkmate circular
166
+ continue-on-error: true
167
+
168
+ license-check:
169
+ name: License Check
170
+ runs-on: ubuntu-latest
171
+ steps:
172
+ - name: Checkout code
173
+ uses: actions/checkout@v4
174
+
175
+ - name: Setup Node.js
176
+ uses: actions/setup-node@v4
177
+ with:
178
+ node-version: 20
179
+
180
+ - name: Install dependencies
181
+ run: npm ci
182
+
183
+ - name: Run License Check
184
+ run: npx pr-checkmate license
185
+ continue-on-error: true
186
+
187
+ pr-size:
188
+ name: PR Size
189
+ runs-on: ubuntu-latest
190
+ steps:
191
+ - name: Checkout code
192
+ uses: actions/checkout@v4
193
+ with:
194
+ fetch-depth: 0
195
+
196
+ - name: Setup Node.js
197
+ uses: actions/setup-node@v4
198
+ with:
199
+ node-version: 20
200
+
201
+ - name: Install dependencies
202
+ run: npm ci
203
+
204
+ - name: Check PR Size
205
+ run: npx pr-checkmate pr-size
206
+ continue-on-error: true
207
+
208
+ pr-title:
209
+ name: PR Title
210
+ runs-on: ubuntu-latest
211
+ steps:
212
+ - name: Checkout code
213
+ uses: actions/checkout@v4
214
+
215
+ - name: Setup Node.js
216
+ uses: actions/setup-node@v4
217
+ with:
218
+ node-version: 20
219
+
220
+ - name: Install dependencies
221
+ run: npm ci
222
+
223
+ - name: Check PR Title
224
+ run: npx pr-checkmate pr-title
225
+ continue-on-error: true
226
+
227
+ outdated-deps:
228
+ name: Outdated Dependencies
229
+ runs-on: ubuntu-latest
230
+ steps:
231
+ - name: Checkout code
232
+ uses: actions/checkout@v4
233
+
234
+ - name: Setup Node.js
235
+ uses: actions/setup-node@v4
236
+ with:
237
+ node-version: 20
238
+
239
+ - name: Install dependencies
240
+ run: npm ci
241
+
242
+ - name: Check Outdated Dependencies
243
+ run: npx pr-checkmate outdated
244
+ continue-on-error: true