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.
Files changed (140) hide show
  1. package/README.md +101 -333
  2. package/cspell.json +9 -1
  3. package/dist/cli.js +32 -2
  4. package/dist/config/constants.d.ts +25 -1
  5. package/dist/config/constants.js +157 -38
  6. package/dist/config/index.d.ts +15 -2
  7. package/dist/config/index.js +28 -7
  8. package/dist/config/loader.js +5 -1
  9. package/dist/core/checks/dependencies/banned-imports.d.ts +2 -0
  10. package/dist/core/checks/dependencies/banned-imports.js +71 -0
  11. package/dist/core/checks/{circular-deps.d.ts → dependencies/circular-deps.d.ts} +1 -1
  12. package/dist/core/checks/{circular-deps.js → dependencies/circular-deps.js} +9 -10
  13. package/dist/core/checks/{dependency-check.d.ts → dependencies/dependency-check.d.ts} +1 -1
  14. package/dist/core/checks/{dependency-check.js → dependencies/dependency-check.js} +3 -3
  15. package/dist/core/checks/{license-check.d.ts → dependencies/license-check.d.ts} +1 -1
  16. package/dist/core/checks/{license-check.js → dependencies/license-check.js} +3 -3
  17. package/dist/core/checks/{npm-audit.d.ts → dependencies/npm-audit.d.ts} +1 -1
  18. package/dist/core/checks/{npm-audit.js → dependencies/npm-audit.js} +3 -3
  19. package/dist/core/checks/{outdated-deps.d.ts → dependencies/outdated-deps.d.ts} +1 -1
  20. package/dist/core/checks/{outdated-deps.js → dependencies/outdated-deps.js} +3 -3
  21. package/dist/core/checks/dependencies/vuln-scan.d.ts +9 -0
  22. package/dist/core/checks/dependencies/vuln-scan.js +41 -0
  23. package/dist/core/checks/findings.d.ts +37 -1
  24. package/dist/core/checks/findings.js +80 -3
  25. package/dist/core/checks/git/custom-rules.d.ts +2 -0
  26. package/dist/core/checks/git/custom-rules.js +102 -0
  27. package/dist/core/checks/{diff-smell.d.ts → git/diff-smell.d.ts} +1 -1
  28. package/dist/core/checks/{diff-smell.js → git/diff-smell.js} +3 -3
  29. package/dist/core/checks/git/large-files.d.ts +2 -0
  30. package/dist/core/checks/git/large-files.js +83 -0
  31. package/dist/core/checks/git/leftover-debug.d.ts +2 -0
  32. package/dist/core/checks/git/leftover-debug.js +77 -0
  33. package/dist/core/checks/git/lockfile-drift.d.ts +2 -0
  34. package/dist/core/checks/git/lockfile-drift.js +114 -0
  35. package/dist/core/checks/git/merge-conflict.d.ts +2 -0
  36. package/dist/core/checks/git/merge-conflict.js +109 -0
  37. package/dist/core/checks/git/missing-tests.d.ts +2 -0
  38. package/dist/core/checks/git/missing-tests.js +92 -0
  39. package/dist/core/checks/git/todo-fixme.d.ts +7 -0
  40. package/dist/core/checks/git/todo-fixme.js +74 -0
  41. package/dist/core/checks/{cpp-format.d.ts → languages/cpp-format.d.ts} +1 -1
  42. package/dist/core/checks/{cpp-format.js → languages/cpp-format.js} +3 -3
  43. package/dist/core/checks/languages/csharp-format.d.ts +13 -0
  44. package/dist/core/checks/languages/csharp-format.js +52 -0
  45. package/dist/core/checks/languages/go-format.d.ts +8 -0
  46. package/dist/core/checks/languages/go-format.js +48 -0
  47. package/dist/core/checks/languages/go-lint.d.ts +8 -0
  48. package/dist/core/checks/languages/go-lint.js +48 -0
  49. package/dist/core/checks/{kotlin-lint.d.ts → languages/kotlin-lint.d.ts} +1 -1
  50. package/dist/core/checks/{kotlin-lint.js → languages/kotlin-lint.js} +13 -17
  51. package/dist/core/checks/{lint.d.ts → languages/lint.d.ts} +1 -1
  52. package/dist/core/checks/{lint.js → languages/lint.js} +25 -14
  53. package/dist/core/checks/languages/php-format.d.ts +9 -0
  54. package/dist/core/checks/languages/php-format.js +49 -0
  55. package/dist/core/checks/{prettier.d.ts → languages/prettier.d.ts} +1 -1
  56. package/dist/core/checks/{prettier.js → languages/prettier.js} +10 -10
  57. package/dist/core/checks/{python-format.d.ts → languages/python-format.d.ts} +1 -1
  58. package/dist/core/checks/{python-format.js → languages/python-format.js} +3 -3
  59. package/dist/core/checks/{python-lint.d.ts → languages/python-lint.d.ts} +1 -1
  60. package/dist/core/checks/{python-lint.js → languages/python-lint.js} +3 -3
  61. package/dist/core/checks/languages/python-typecheck.d.ts +9 -0
  62. package/dist/core/checks/languages/python-typecheck.js +66 -0
  63. package/dist/core/checks/languages/ruby-lint.d.ts +8 -0
  64. package/dist/core/checks/languages/ruby-lint.js +50 -0
  65. package/dist/core/checks/languages/rust-format.d.ts +9 -0
  66. package/dist/core/checks/languages/rust-format.js +45 -0
  67. package/dist/core/checks/languages/rust-lint.d.ts +8 -0
  68. package/dist/core/checks/languages/rust-lint.js +50 -0
  69. package/dist/core/checks/{swift-lint.d.ts → languages/swift-lint.d.ts} +1 -1
  70. package/dist/core/checks/{swift-lint.js → languages/swift-lint.js} +13 -17
  71. package/dist/core/checks/{typecheck.d.ts → languages/typecheck.d.ts} +1 -1
  72. package/dist/core/checks/{typecheck.js → languages/typecheck.js} +3 -3
  73. package/dist/core/checks/{commitlint.d.ts → pr/commitlint.d.ts} +1 -1
  74. package/dist/core/checks/{commitlint.js → pr/commitlint.js} +4 -4
  75. package/dist/core/checks/{pr-body.d.ts → pr/pr-body.d.ts} +1 -1
  76. package/dist/core/checks/{pr-body.js → pr/pr-body.js} +2 -2
  77. package/dist/core/checks/{pr-size-check.d.ts → pr/pr-size-check.d.ts} +1 -1
  78. package/dist/core/checks/{pr-size-check.js → pr/pr-size-check.js} +13 -11
  79. package/dist/core/checks/{pr-title-lint.d.ts → pr/pr-title-lint.d.ts} +1 -1
  80. package/dist/core/checks/{pr-title-lint.js → pr/pr-title-lint.js} +2 -2
  81. package/dist/core/checks/quality/case-collision.d.ts +8 -0
  82. package/dist/core/checks/quality/case-collision.js +40 -0
  83. package/dist/core/checks/quality/config-validation.d.ts +8 -0
  84. package/dist/core/checks/quality/config-validation.js +63 -0
  85. package/dist/core/checks/quality/coverage.d.ts +2 -0
  86. package/dist/core/checks/quality/coverage.js +63 -0
  87. package/dist/core/checks/{dead-code.d.ts → quality/dead-code.d.ts} +1 -1
  88. package/dist/core/checks/{dead-code.js → quality/dead-code.js} +4 -4
  89. package/dist/core/checks/{duplicate-check.d.ts → quality/duplicate-check.d.ts} +1 -1
  90. package/dist/core/checks/{duplicate-check.js → quality/duplicate-check.js} +11 -15
  91. package/dist/core/checks/quality/license-header.d.ts +7 -0
  92. package/dist/core/checks/quality/license-header.js +74 -0
  93. package/dist/core/checks/{markdown-lint.d.ts → quality/markdown-lint.d.ts} +1 -1
  94. package/dist/core/checks/{markdown-lint.js → quality/markdown-lint.js} +8 -21
  95. package/dist/core/checks/{spellcheck.d.ts → quality/spellcheck.d.ts} +1 -1
  96. package/dist/core/checks/{spellcheck.js → quality/spellcheck.js} +11 -19
  97. package/dist/core/checks/{diff-security.d.ts → security/diff-security.d.ts} +1 -1
  98. package/dist/core/checks/security/diff-security.js +262 -0
  99. package/dist/core/checks/security/dockerfile-security.d.ts +2 -0
  100. package/dist/core/checks/security/dockerfile-security.js +92 -0
  101. package/dist/core/checks/security/migration-safety.d.ts +2 -0
  102. package/dist/core/checks/security/migration-safety.js +110 -0
  103. package/dist/core/checks/{security.d.ts → security/security.d.ts} +1 -1
  104. package/dist/core/checks/{security.js → security/security.js} +4 -4
  105. package/dist/core/checks/{sensitive-file-guard.d.ts → security/sensitive-file-guard.d.ts} +1 -1
  106. package/dist/core/checks/{sensitive-file-guard.js → security/sensitive-file-guard.js} +4 -4
  107. package/dist/core/checks/security/workflow-security.d.ts +2 -0
  108. package/dist/core/checks/security/workflow-security.js +75 -0
  109. package/dist/core/context.js +54 -10
  110. package/dist/core/registry.js +73 -28
  111. package/dist/core/reporters.d.ts +4 -3
  112. package/dist/core/reporters.js +104 -4
  113. package/dist/core/run-checks.js +21 -3
  114. package/dist/core/targets.d.ts +17 -1
  115. package/dist/core/targets.js +74 -4
  116. package/dist/core/types.d.ts +13 -1
  117. package/dist/index.d.ts +1 -1
  118. package/dist/index.js +3 -1
  119. package/dist/init.js +86 -8
  120. package/dist/interfaces/index.d.ts +101 -1
  121. package/dist/scripts/copy-configs.js +6 -1
  122. package/dist/utils/detect-language.d.ts +1 -1
  123. package/dist/utils/detect-language.js +32 -3
  124. package/dist/utils/glob.d.ts +10 -0
  125. package/dist/utils/glob.js +25 -0
  126. package/dist/utils/index.d.ts +1 -1
  127. package/dist/utils/index.js +1 -1
  128. package/eslint-default-rules.json +62 -0
  129. package/eslint.config.mjs +6 -66
  130. package/package.json +3 -1
  131. package/pr-checkmate.schema.json +166 -0
  132. package/src/config/cspell.json +9 -1
  133. package/src/config/eslint-default-rules.json +62 -0
  134. package/src/config/pr-checkmate.schema.json +166 -0
  135. package/dist/core/checks/diff-security.js +0 -145
  136. package/dist/utils/delta.d.ts +0 -5
  137. package/dist/utils/delta.js +0 -53
  138. package/src/config/eslint.config.mjs +0 -180
  139. /package/dist/core/checks/{ruff-shared.d.ts → languages/ruff-shared.d.ts} +0 -0
  140. /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
- };
@@ -1,5 +0,0 @@
1
- /**
2
- * Returns list of changed files in the current PR filtered by extension.
3
- * Returns null when not in a GitHub PR context (falls back to full-project scan).
4
- */
5
- export declare function getChangedFiles(extensions: string[]): Promise<string[] | null>;
@@ -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
- ];