pr-checkmate 1.21.7 → 1.21.9

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
@@ -21,7 +21,7 @@ function loadUserConfig() {
21
21
  if (fs.existsSync(configPath)) {
22
22
  try {
23
23
  const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
24
- console.log(`[ESLint]: ✅ Loaded config from: ${configPath}`);
24
+ console.error(`[ESLint]: ✅ Loaded config from: ${configPath}`);
25
25
  return config;
26
26
  } catch (err) {
27
27
  console.warn(`[ESLint]: ⚠️ Failed to parse ${configPath}:`, err.message);
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
+ # ♟️ PR CheckMate
2
+
1
3
  ![Build](https://img.shields.io/github/actions/workflow/status/Mybono/sdk_automation/publish.yml?branch=main&label=CI&color=blue)
2
4
  ![ESLint](https://img.shields.io/npm/v/eslint?color=yellow&label=ESLint)
3
5
  ![Prettier](https://img.shields.io/npm/v/prettier?color=orange&label=Prettier)
4
6
 
5
- # ♟️ PR CheckMate
6
- >
7
7
  > **PR CheckMate** is an npm package for automating Pull Request checks.
8
8
  > It helps teams maintain code quality by automatically validating linting, formatting, dependencies, security, and spelling before merging to `main`.
9
9
 
package/cspell.json CHANGED
@@ -2,11 +2,11 @@
2
2
  "version": "0.2",
3
3
  "language": "en,ru,uk,he,fr,es",
4
4
  "import": [
5
- "./node_modules/@cspell/dict-ru_ru/cspell-ext.json",
6
- "./node_modules/@cspell/dict-uk-ua/cspell-ext.json",
7
- "./node_modules/@cspell/dict-he/cspell-ext.json",
8
- "./node_modules/@cspell/dict-fr-fr/cspell-ext.json",
9
- "./node_modules/@cspell/dict-es-es/cspell-ext.json"
5
+ "@cspell/dict-ru_ru/cspell-ext.json",
6
+ "@cspell/dict-uk-ua/cspell-ext.json",
7
+ "@cspell/dict-he/cspell-ext.json",
8
+ "@cspell/dict-fr-fr/cspell-ext.json",
9
+ "@cspell/dict-es-es/cspell-ext.json"
10
10
  ],
11
11
  "words": [
12
12
  "ACMR",
@@ -59,6 +59,16 @@ function mergeWithDefaults(userConfig) {
59
59
  prBody: { ...defaults.prBody, ...userConfig.prBody },
60
60
  duplicate: { ...defaults.duplicate, ...userConfig.duplicate },
61
61
  commitlint: { ...defaults.commitlint, ...userConfig.commitlint },
62
+ licenseCheck: {
63
+ allowPackages: [
64
+ ...(defaults.licenseCheck?.allowPackages || []),
65
+ ...(userConfig.licenseCheck?.allowPackages || []),
66
+ ],
67
+ allowLicenses: [
68
+ ...(defaults.licenseCheck?.allowLicenses || []),
69
+ ...(userConfig.licenseCheck?.allowLicenses || []),
70
+ ],
71
+ },
62
72
  };
63
73
  }
64
74
  /**
@@ -39,7 +39,11 @@ const DEFAULT_TYPES = [
39
39
  ];
40
40
  function buildTempConfig(types) {
41
41
  const config = {
42
- extends: [(0, utils_1.resolvePackageBin)('@commitlint/config-conventional', 'index.js')],
42
+ // Resolve the config package to its real entry point via Node module
43
+ // resolution. It works regardless of npm hoisting in the client project and
44
+ // regardless of the package's internal layout (e.g. lib/index.js vs index.js)
45
+ // or exports map — unlike hardcoding a subpath.
46
+ extends: [require.resolve('@commitlint/config-conventional')],
43
47
  rules: {
44
48
  'type-enum': [2, 'always', types],
45
49
  },
@@ -73,7 +77,7 @@ async function runCommitlint() {
73
77
  result_collector_1.resultCollector.register('Commitlint', 'skip');
74
78
  return;
75
79
  }
76
- utils_1.logger.info('[runCommitlint]: 📝 Running commitlint...');
80
+ utils_1.logger.info('[runCommitlint]: Running commitlint...');
77
81
  const commitlintBin = (0, utils_1.resolvePackageBin)('@commitlint/cli', 'cli.js');
78
82
  const hasLocal = (0, config_1.hasLocalConfig)(LOCAL_CONFIG_FILES);
79
83
  let tempConfigFile = null;
@@ -11,7 +11,6 @@ const configFiles = [
11
11
  { source: 'src/config/eslint.config.mjs', dest: 'eslint.config.mjs' },
12
12
  { source: 'src/config/.eslintrc.js', dest: '.eslintrc.js' },
13
13
  { source: 'src/config/.prettierrc', dest: '.prettierrc' },
14
- { source: 'src/config/.eslintignore', dest: '.eslintignore' },
15
14
  { source: 'src/config/cspell.json', dest: 'cspell.json' },
16
15
  { source: 'tsconfig.json', dest: 'tsconfig.json' },
17
16
  { source: 'src/config/pr-checkmate-workflow.yml', dest: 'dist/config/pr-checkmate-workflow.yml' },
@@ -30,9 +30,14 @@ async function runDependencyCheck() {
30
30
  throw err;
31
31
  }
32
32
  }
33
+ // Tools loaded by depcheck (e.g. eslint configs) may print to stdout ahead of
34
+ // the JSON, so slice from the first "{" to the last "}" before parsing.
35
+ const start = stdout.indexOf('{');
36
+ const end = stdout.lastIndexOf('}');
37
+ const json = start !== -1 && end !== -1 ? stdout.slice(start, end + 1) : stdout;
33
38
  let result;
34
39
  try {
35
- result = JSON.parse(stdout);
40
+ result = JSON.parse(json);
36
41
  }
37
42
  catch {
38
43
  utils_1.logger.error('[runDependencyCheck]: ❌ Failed to parse depcheck output');
@@ -84,7 +84,7 @@ async function trackSoftCheck(name, fn) {
84
84
  }
85
85
  }
86
86
  async function runJob(jobName) {
87
- utils_1.logger.info(`[runJob]: 🚀 Running job: ${jobName}`);
87
+ utils_1.logger.info(`[runJob]: Running job: ${jobName}`);
88
88
  try {
89
89
  switch (jobName) {
90
90
  case 'all':
@@ -6,11 +6,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runLicenseCheck = runLicenseCheck;
7
7
  const execa_1 = require("execa");
8
8
  const utils_1 = require("../utils");
9
+ const loader_1 = require("../config/loader");
9
10
  const node_path_1 = __importDefault(require("node:path"));
10
11
  const node_fs_1 = __importDefault(require("node:fs"));
11
12
  const FORBIDDEN_LICENSES = ['GPL-2.0', 'GPL-3.0', 'AGPL-3.0', 'LGPL-2.0', 'LGPL-2.1', 'LGPL-3.0'];
13
+ /**
14
+ * Strip the trailing "@version" from a license-checker key to get the bare
15
+ * package name. Handles scoped packages, e.g. "@cspell/dict-ru_ru@2.3.2" → "@cspell/dict-ru_ru".
16
+ */
17
+ function bareName(pkgKey) {
18
+ const at = pkgKey.lastIndexOf('@');
19
+ return at > 0 ? pkgKey.slice(0, at) : pkgKey;
20
+ }
12
21
  async function runLicenseCheck() {
13
22
  utils_1.logger.info('[runLicenseCheck]: Checking dependency licenses...');
23
+ const cfg = (0, loader_1.loadProjectConfig)();
24
+ const allowPackages = new Set(cfg.licenseCheck?.allowPackages ?? []);
25
+ const allowLicenses = cfg.licenseCheck?.allowLicenses ?? [];
14
26
  if (!node_fs_1.default.existsSync(node_path_1.default.join(process.cwd(), 'package.json'))) {
15
27
  utils_1.logger.warn('[runLicenseCheck]: ⚠️ No package.json found, skipping');
16
28
  return;
@@ -22,8 +34,12 @@ async function runLicenseCheck() {
22
34
  const licenses = JSON.parse(stdout);
23
35
  const violations = [];
24
36
  for (const [pkg, info] of Object.entries(licenses)) {
37
+ if (allowPackages.has(bareName(pkg)))
38
+ continue;
25
39
  const raw = info.licenses ?? '';
26
40
  const license = Array.isArray(raw) ? raw.join(' OR ') : raw;
41
+ if (allowLicenses.some(a => license.includes(a)))
42
+ continue;
27
43
  if (FORBIDDEN_LICENSES.some(f => license.includes(f))) {
28
44
  violations.push(` ${pkg}: ${license}`);
29
45
  }
@@ -21,7 +21,7 @@ async function getESLintMajorVersion() {
21
21
  }
22
22
  }
23
23
  async function runLint() {
24
- utils_1.logger.info('[runLint]: 🔍 Running ESLint...');
24
+ utils_1.logger.info('[runLint]: Running ESLint...');
25
25
  const eslintBin = (0, utils_1.resolvePackageBin)('eslint', 'bin/eslint.js');
26
26
  const projectRoot = process.cwd();
27
27
  const sourcePath = (0, config_1.getSourcePath)();
@@ -33,7 +33,7 @@ function buildMergedConfig(bundledConfigPath, userRules) {
33
33
  return tmpFile;
34
34
  }
35
35
  async function runMarkdownLint() {
36
- utils_1.logger.info('[runMarkdownLint]: 📝 Running Markdown lint...');
36
+ utils_1.logger.info('[runMarkdownLint]: Running Markdown lint...');
37
37
  const root = process.cwd();
38
38
  const changedFiles = await (0, delta_1.getChangedFiles)(['.md', '.mdx']);
39
39
  let targets;
@@ -53,7 +53,7 @@ async function getBaseSha() {
53
53
  * Run security scan for secrets
54
54
  */
55
55
  async function runSecurityScan() {
56
- utils_1.logger.info('🔐 Running security scan with gitleaks-secret-scanner...');
56
+ utils_1.logger.info('Running security scan with gitleaks-secret-scanner...');
57
57
  try {
58
58
  const headSha = await getHeadSha();
59
59
  if (!headSha) {
@@ -35,8 +35,22 @@ function createTempCspellConfig() {
35
35
  const packageConfigDir = node_path_1.default.dirname(packageConfigPath);
36
36
  const defaultConfig = JSON.parse(node_fs_1.default.readFileSync(packageConfigPath, 'utf-8'));
37
37
  const userConfig = loadUserCspellConfig();
38
- // Resolve relative import paths to absolute so they work from any client cwd
39
- const resolvedImports = (defaultConfig.import ?? []).map(p => p.startsWith('.') ? node_path_1.default.resolve(packageConfigDir, p) : p);
38
+ // Resolve import paths to absolute so they work from any client cwd.
39
+ // Relative paths are resolved against the package config dir; bare package
40
+ // specifiers (e.g. "@cspell/dict-ru_ru/cspell-ext.json") are resolved via Node
41
+ // module resolution so they work regardless of npm hoisting in the client
42
+ // project (dicts may live in the root node_modules, not nested under us).
43
+ const resolvedImports = (defaultConfig.import ?? []).map(p => {
44
+ if (p.startsWith('.')) {
45
+ return node_path_1.default.resolve(packageConfigDir, p);
46
+ }
47
+ try {
48
+ return require.resolve(p);
49
+ }
50
+ catch {
51
+ return p;
52
+ }
53
+ });
40
54
  // Merge configurations
41
55
  const mergedConfig = {
42
56
  ...defaultConfig,
@@ -87,7 +101,7 @@ async function runSpellcheck() {
87
101
  let tempConfigPath = null;
88
102
  const cspellBin = (0, utils_1.resolvePackageBin)('cspell', 'bin.mjs');
89
103
  if (hasLocal) {
90
- utils_1.logger.info(`📋 Using local cspell config (checking: ${sourcePath})`);
104
+ utils_1.logger.info(`Using local cspell config (checking: ${sourcePath})`);
91
105
  args = [...patterns, '--no-progress'];
92
106
  }
93
107
  else {
@@ -9,6 +9,22 @@ const utils_1 = require("../utils");
9
9
  const loader_1 = require("../config/loader");
10
10
  const node_fs_1 = __importDefault(require("node:fs"));
11
11
  const node_path_1 = __importDefault(require("node:path"));
12
+ /**
13
+ * Resolves the `tsc` binary, preferring the consumer project's own TypeScript so its
14
+ * tsconfig is compiled by the version it was written for. Falls back to the TypeScript
15
+ * bundled with pr-checkmate when the project has no local install.
16
+ */
17
+ function resolveTsc() {
18
+ try {
19
+ const localTsc = (0, utils_1.resolvePackageBin)('typescript', 'bin/tsc', { paths: [process.cwd()] });
20
+ utils_1.logger.info("[runTypecheck]: Using project's local TypeScript");
21
+ return localTsc;
22
+ }
23
+ catch {
24
+ utils_1.logger.info('[runTypecheck]: No local TypeScript found, using bundled compiler');
25
+ return (0, utils_1.resolvePackageBin)('typescript', 'bin/tsc');
26
+ }
27
+ }
12
28
  async function runTypecheck() {
13
29
  const cfg = (0, loader_1.loadProjectConfig)();
14
30
  if (cfg.typecheck?.enabled === false) {
@@ -21,7 +37,7 @@ async function runTypecheck() {
21
37
  utils_1.logger.info('[runTypecheck]: No tsconfig.json found, skipping');
22
38
  return;
23
39
  }
24
- const tscBin = (0, utils_1.resolvePackageBin)('typescript', 'bin/tsc');
40
+ const tscBin = resolveTsc();
25
41
  const result = await (0, execa_1.execa)(process.execPath, [tscBin, '--noEmit'], { reject: false });
26
42
  if (result.exitCode !== 0) {
27
43
  const output = [result.stdout, result.stderr].filter(Boolean).join('\n');
@@ -13,21 +13,25 @@ const node_fs_1 = __importDefault(require("node:fs"));
13
13
  * 1. Direct subpath — fast path for packages that explicitly export their bin
14
14
  * 2. Via package.json — for packages that export ./package.json but not the bin subpath (e.g. eslint)
15
15
  * 3. Walk up from main entry — for packages that export neither (e.g. cspell)
16
+ *
17
+ * @param options.paths - Directories to resolve from (passed to `require.resolve`).
18
+ * Use `[process.cwd()]` to prefer the consumer project's copy of the package.
16
19
  */
17
- function resolvePackageBin(pkgName, binRelPath) {
20
+ function resolvePackageBin(pkgName, binRelPath, options) {
21
+ const resolveOpts = options?.paths ? { paths: options.paths } : undefined;
18
22
  // 1. Direct subpath
19
23
  try {
20
- return require.resolve(`${pkgName}/${binRelPath}`);
24
+ return require.resolve(`${pkgName}/${binRelPath}`, resolveOpts);
21
25
  }
22
26
  catch { }
23
27
  // 2. Via package.json
24
28
  try {
25
- const pkgJsonPath = require.resolve(`${pkgName}/package.json`);
29
+ const pkgJsonPath = require.resolve(`${pkgName}/package.json`, resolveOpts);
26
30
  return node_path_1.default.join(node_path_1.default.dirname(pkgJsonPath), binRelPath);
27
31
  }
28
32
  catch { }
29
33
  // 3. Walk up from main entry to find package root by matching package name
30
- const main = require.resolve(pkgName);
34
+ const main = require.resolve(pkgName, resolveOpts);
31
35
  let dir = node_path_1.default.dirname(main);
32
36
  while (dir !== node_path_1.default.dirname(dir)) {
33
37
  const pkgJsonPath = node_path_1.default.join(dir, 'package.json');
package/eslint.config.mjs CHANGED
@@ -76,13 +76,13 @@ function loadUserConfig() {
76
76
  if (fs.existsSync(configPath)) {
77
77
  try {
78
78
  const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
79
- console.log(`[loadUserConfig]: ✅ Loaded user config from: ${configPath}`);
79
+ console.error(`[loadUserConfig]: ✅ Loaded user config from: ${configPath}`);
80
80
  return config;
81
81
  } catch (err) {
82
82
  console.warn(`[loadUserConfig]: ⚠️ Failed to parse ${configPath}:`, err.message);
83
83
  }
84
84
  } else {
85
- console.log(`[loadUserConfig]: ℹ️ No pr-checkmate.json found, using defaults`);
85
+ console.error(`[loadUserConfig]: ℹ️ No pr-checkmate.json found, using defaults`);
86
86
  }
87
87
 
88
88
  return { sourcePath: 'src', eslint: {} };
@@ -110,13 +110,13 @@ const customRulesCount = Object.keys(userConfig.eslint?.rules || {}).length;
110
110
  const customIgnoresCount = (userConfig.eslint?.ignorePatterns || []).length;
111
111
 
112
112
  if (customRulesCount > 0) {
113
- console.log(`🔧 Applied ${customRulesCount} custom ESLint rules`);
113
+ console.error(`🔧 Applied ${customRulesCount} custom ESLint rules`);
114
114
  }
115
115
  if (customIgnoresCount > 0) {
116
- console.log(`🚫 Applied ${customIgnoresCount} custom ignore patterns`);
116
+ console.error(`🚫 Applied ${customIgnoresCount} custom ignore patterns`);
117
117
  }
118
118
 
119
- console.log(`📋 ESLint checking: ${SRC}/**/*.{ts,tsx,js,jsx}`);
119
+ console.error(`📋 ESLint checking: ${SRC}/**/*.{ts,tsx,js,jsx}`);
120
120
 
121
121
  export default [
122
122
  // Global ignores must be in a separate config object
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pr-checkmate",
3
- "version": "1.21.7",
3
+ "version": "1.21.9",
4
4
  "description": "Automated PR quality checks: linting, formatting, dependency analysis, and spellcheck",
5
5
  "keywords": [
6
6
  "github-actions",
@@ -23,7 +23,6 @@
23
23
  "eslint.config.mjs",
24
24
  ".eslintrc.js",
25
25
  ".prettierrc",
26
- ".eslintignore",
27
26
  "cspell.json",
28
27
  "src/config/pr-checkmate-workflow.yml",
29
28
  ".markdownlint.json",
@@ -67,10 +66,10 @@
67
66
  "@cspell/dict-he": "^4.0.2",
68
67
  "@cspell/dict-ru_ru": "^2.2.1",
69
68
  "@cspell/dict-uk-ua": "^4.0.0",
69
+ "@types/node": "^25.9.4",
70
70
  "@typescript-eslint/eslint-plugin": "^8.47.0",
71
71
  "@typescript-eslint/parser": "^8.47.0",
72
72
  "cspell": "^9.3.2",
73
- "dotenv": "^17.2.3",
74
73
  "eslint": "^9.26.0",
75
74
  "eslint-config-prettier": "^9.1.2",
76
75
  "eslint-plugin-import": "^2.29.0",
@@ -21,7 +21,7 @@ function loadUserConfig() {
21
21
  if (fs.existsSync(configPath)) {
22
22
  try {
23
23
  const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
24
- console.log(`[ESLint]: ✅ Loaded config from: ${configPath}`);
24
+ console.error(`[ESLint]: ✅ Loaded config from: ${configPath}`);
25
25
  return config;
26
26
  } catch (err) {
27
27
  console.warn(`[ESLint]: ⚠️ Failed to parse ${configPath}:`, err.message);
@@ -2,11 +2,11 @@
2
2
  "version": "0.2",
3
3
  "language": "en,ru,uk,he,fr,es",
4
4
  "import": [
5
- "./node_modules/@cspell/dict-ru_ru/cspell-ext.json",
6
- "./node_modules/@cspell/dict-uk-ua/cspell-ext.json",
7
- "./node_modules/@cspell/dict-he/cspell-ext.json",
8
- "./node_modules/@cspell/dict-fr-fr/cspell-ext.json",
9
- "./node_modules/@cspell/dict-es-es/cspell-ext.json"
5
+ "@cspell/dict-ru_ru/cspell-ext.json",
6
+ "@cspell/dict-uk-ua/cspell-ext.json",
7
+ "@cspell/dict-he/cspell-ext.json",
8
+ "@cspell/dict-fr-fr/cspell-ext.json",
9
+ "@cspell/dict-es-es/cspell-ext.json"
10
10
  ],
11
11
  "words": [
12
12
  "ACMR",
@@ -76,13 +76,13 @@ function loadUserConfig() {
76
76
  if (fs.existsSync(configPath)) {
77
77
  try {
78
78
  const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
79
- console.log(`[loadUserConfig]: ✅ Loaded user config from: ${configPath}`);
79
+ console.error(`[loadUserConfig]: ✅ Loaded user config from: ${configPath}`);
80
80
  return config;
81
81
  } catch (err) {
82
82
  console.warn(`[loadUserConfig]: ⚠️ Failed to parse ${configPath}:`, err.message);
83
83
  }
84
84
  } else {
85
- console.log(`[loadUserConfig]: ℹ️ No pr-checkmate.json found, using defaults`);
85
+ console.error(`[loadUserConfig]: ℹ️ No pr-checkmate.json found, using defaults`);
86
86
  }
87
87
 
88
88
  return { sourcePath: 'src', eslint: {} };
@@ -110,13 +110,13 @@ const customRulesCount = Object.keys(userConfig.eslint?.rules || {}).length;
110
110
  const customIgnoresCount = (userConfig.eslint?.ignorePatterns || []).length;
111
111
 
112
112
  if (customRulesCount > 0) {
113
- console.log(`🔧 Applied ${customRulesCount} custom ESLint rules`);
113
+ console.error(`🔧 Applied ${customRulesCount} custom ESLint rules`);
114
114
  }
115
115
  if (customIgnoresCount > 0) {
116
- console.log(`🚫 Applied ${customIgnoresCount} custom ignore patterns`);
116
+ console.error(`🚫 Applied ${customIgnoresCount} custom ignore patterns`);
117
117
  }
118
118
 
119
- console.log(`📋 ESLint checking: ${SRC}/**/*.{ts,tsx,js,jsx}`);
119
+ console.error(`📋 ESLint checking: ${SRC}/**/*.{ts,tsx,js,jsx}`);
120
120
 
121
121
  export default [
122
122
  // Global ignores must be in a separate config object
package/.eslintignore DELETED
@@ -1,72 +0,0 @@
1
- # Dependencies
2
- node_modules/
3
-
4
- # Build outputs
5
- dist/
6
- build/
7
- out/
8
- .next/
9
- .nuxt/
10
-
11
- # Test reports & artifacts
12
- allure-report/
13
- allure-results/
14
- reports/
15
- report/
16
- test-reports/
17
- test-report/
18
- test-output/
19
- test-results/
20
- results/
21
- result/
22
- coverage/
23
- .coverage/
24
- htmlcov/
25
-
26
- # Jest
27
- jest-html-reporters-*/
28
- jest-stare/
29
- jest.config.js
30
-
31
- # Cypress
32
- cypress/reports/
33
- cypress/videos/
34
- cypress/screenshots/
35
-
36
- # Playwright
37
- playwright-report/
38
- test-results/
39
-
40
- # WebdriverIO
41
- .wdio/
42
- wdio-logs/
43
-
44
- # Mocha/Mochawesome
45
- mochawesome-report/
46
- mochawesome-reports/
47
-
48
- # Maven/JUnit
49
- target/
50
-
51
- # Logs
52
- logs/
53
- *.log
54
- npm-debug.log*
55
- yarn-debug.log*
56
-
57
- # Python
58
- __pycache__/
59
- .pytest_cache/
60
- .venv/
61
- venv/
62
-
63
- # Git
64
- .git/
65
-
66
- # Config files
67
- *.config.js
68
- *.config.ts
69
- jest.config.*
70
- wdio.config.*
71
- playwright.config.*
72
- cypress.config.*
@@ -1,72 +0,0 @@
1
- # Dependencies
2
- node_modules/
3
-
4
- # Build outputs
5
- dist/
6
- build/
7
- out/
8
- .next/
9
- .nuxt/
10
-
11
- # Test reports & artifacts
12
- allure-report/
13
- allure-results/
14
- reports/
15
- report/
16
- test-reports/
17
- test-report/
18
- test-output/
19
- test-results/
20
- results/
21
- result/
22
- coverage/
23
- .coverage/
24
- htmlcov/
25
-
26
- # Jest
27
- jest-html-reporters-*/
28
- jest-stare/
29
- jest.config.js
30
-
31
- # Cypress
32
- cypress/reports/
33
- cypress/videos/
34
- cypress/screenshots/
35
-
36
- # Playwright
37
- playwright-report/
38
- test-results/
39
-
40
- # WebdriverIO
41
- .wdio/
42
- wdio-logs/
43
-
44
- # Mocha/Mochawesome
45
- mochawesome-report/
46
- mochawesome-reports/
47
-
48
- # Maven/JUnit
49
- target/
50
-
51
- # Logs
52
- logs/
53
- *.log
54
- npm-debug.log*
55
- yarn-debug.log*
56
-
57
- # Python
58
- __pycache__/
59
- .pytest_cache/
60
- .venv/
61
- venv/
62
-
63
- # Git
64
- .git/
65
-
66
- # Config files
67
- *.config.js
68
- *.config.ts
69
- jest.config.*
70
- wdio.config.*
71
- playwright.config.*
72
- cypress.config.*