commit-cop 1.1.0 → 1.1.2

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 (130) hide show
  1. package/README.md +72 -15
  2. package/dist/brand.d.ts +4 -0
  3. package/dist/brand.d.ts.map +1 -0
  4. package/{src/brand.ts → dist/brand.js} +4 -3
  5. package/dist/brand.js.map +1 -0
  6. package/dist/checks/binaryFileCheck.js +2 -2
  7. package/dist/checks/binaryFileCheck.js.map +1 -1
  8. package/dist/checks/consoleLogCheck.d.ts.map +1 -1
  9. package/dist/checks/consoleLogCheck.js +2 -2
  10. package/dist/checks/consoleLogCheck.js.map +1 -1
  11. package/dist/checks/debuggerCheck.d.ts.map +1 -1
  12. package/dist/checks/debuggerCheck.js +2 -2
  13. package/dist/checks/debuggerCheck.js.map +1 -1
  14. package/dist/checks/envFileCheck.d.ts.map +1 -1
  15. package/dist/checks/envFileCheck.js +2 -2
  16. package/dist/checks/envFileCheck.js.map +1 -1
  17. package/dist/checks/focusedTestCheck.js +2 -2
  18. package/dist/checks/focusedTestCheck.js.map +1 -1
  19. package/dist/checks/generatedFolderCheck.js +2 -2
  20. package/dist/checks/generatedFolderCheck.js.map +1 -1
  21. package/dist/checks/junkFileCheck.d.ts.map +1 -1
  22. package/dist/checks/junkFileCheck.js +2 -2
  23. package/dist/checks/junkFileCheck.js.map +1 -1
  24. package/dist/checks/largeFileCheck.js +2 -2
  25. package/dist/checks/largeFileCheck.js.map +1 -1
  26. package/dist/checks/localHostCheck.js +2 -2
  27. package/dist/checks/localHostCheck.js.map +1 -1
  28. package/dist/checks/lockfileDriftCheck.d.ts.map +1 -1
  29. package/dist/checks/lockfileDriftCheck.js +4 -4
  30. package/dist/checks/lockfileDriftCheck.js.map +1 -1
  31. package/dist/checks/mergeConflictCheck.d.ts.map +1 -1
  32. package/dist/checks/mergeConflictCheck.js +2 -2
  33. package/dist/checks/mergeConflictCheck.js.map +1 -1
  34. package/dist/checks/secretCheck.js +19 -19
  35. package/dist/checks/secretCheck.js.map +1 -1
  36. package/dist/checks/sensitiveFilenameCheck.d.ts.map +1 -1
  37. package/dist/checks/sensitiveFilenameCheck.js +2 -2
  38. package/dist/checks/sensitiveFilenameCheck.js.map +1 -1
  39. package/dist/fix/debugCode.d.ts +3 -0
  40. package/dist/fix/debugCode.d.ts.map +1 -0
  41. package/dist/fix/debugCode.js +55 -0
  42. package/dist/fix/debugCode.js.map +1 -0
  43. package/dist/fix/focusedTests.d.ts +2 -0
  44. package/dist/fix/focusedTests.d.ts.map +1 -0
  45. package/dist/fix/focusedTests.js +22 -0
  46. package/dist/fix/focusedTests.js.map +1 -0
  47. package/dist/fix/gitignore.d.ts +2 -0
  48. package/dist/fix/gitignore.d.ts.map +1 -0
  49. package/dist/fix/gitignore.js +82 -0
  50. package/dist/fix/gitignore.js.map +1 -0
  51. package/dist/fix/junkFiles.d.ts +2 -0
  52. package/dist/fix/junkFiles.d.ts.map +1 -0
  53. package/dist/fix/junkFiles.js +14 -0
  54. package/dist/fix/junkFiles.js.map +1 -0
  55. package/dist/fix/lockfile.d.ts +2 -0
  56. package/dist/fix/lockfile.d.ts.map +1 -0
  57. package/dist/fix/lockfile.js +18 -0
  58. package/dist/fix/lockfile.js.map +1 -0
  59. package/dist/fix/matchers.d.ts +9 -0
  60. package/dist/fix/matchers.d.ts.map +1 -0
  61. package/dist/fix/matchers.js +118 -0
  62. package/dist/fix/matchers.js.map +1 -0
  63. package/dist/fix/runFix.d.ts +3 -0
  64. package/dist/fix/runFix.d.ts.map +1 -0
  65. package/dist/fix/runFix.js +82 -0
  66. package/dist/fix/runFix.js.map +1 -0
  67. package/dist/fix/unstage.d.ts +2 -0
  68. package/dist/fix/unstage.d.ts.map +1 -0
  69. package/dist/fix/unstage.js +22 -0
  70. package/dist/fix/unstage.js.map +1 -0
  71. package/dist/fix/utils.d.ts +4 -0
  72. package/dist/fix/utils.d.ts.map +1 -0
  73. package/dist/fix/utils.js +39 -0
  74. package/dist/fix/utils.js.map +1 -0
  75. package/dist/git.d.ts.map +1 -1
  76. package/dist/git.js +2 -1
  77. package/dist/git.js.map +1 -1
  78. package/dist/hook.d.ts +3 -0
  79. package/dist/hook.d.ts.map +1 -0
  80. package/dist/hook.js +87 -0
  81. package/dist/hook.js.map +1 -0
  82. package/dist/index.js +38 -21
  83. package/dist/index.js.map +1 -1
  84. package/dist/reporter.d.ts +1 -1
  85. package/dist/reporter.d.ts.map +1 -1
  86. package/dist/reporter.js +86 -28
  87. package/dist/reporter.js.map +1 -1
  88. package/dist/runScan.d.ts +2 -0
  89. package/dist/runScan.d.ts.map +1 -0
  90. package/dist/runScan.js +18 -0
  91. package/dist/runScan.js.map +1 -0
  92. package/dist/scanner.d.ts.map +1 -1
  93. package/dist/scanner.js +4 -1
  94. package/dist/scanner.js.map +1 -1
  95. package/dist/types.d.ts +4 -0
  96. package/dist/types.d.ts.map +1 -1
  97. package/package.json +7 -2
  98. package/src/checks/binaryFileCheck.ts +0 -64
  99. package/src/checks/consoleLogCheck.ts +0 -40
  100. package/src/checks/debuggerCheck.ts +0 -33
  101. package/src/checks/envFileCheck.ts +0 -26
  102. package/src/checks/focusedTestCheck.ts +0 -41
  103. package/src/checks/generatedFolderCheck.ts +0 -45
  104. package/src/checks/junkFileCheck.ts +0 -40
  105. package/src/checks/largeFileCheck.ts +0 -31
  106. package/src/checks/localHostCheck.ts +0 -40
  107. package/src/checks/lockfileDriftCheck.ts +0 -40
  108. package/src/checks/mergeConflictCheck.ts +0 -41
  109. package/src/checks/secretCheck.ts +0 -60
  110. package/src/checks/sensitiveFilenameCheck.ts +0 -51
  111. package/src/checks/utils.ts +0 -62
  112. package/src/fix/debugCode.ts +0 -74
  113. package/src/fix/focusedTests.ts +0 -26
  114. package/src/fix/gitignore.ts +0 -108
  115. package/src/fix/junkFiles.ts +0 -16
  116. package/src/fix/lockfile.ts +0 -23
  117. package/src/fix/matchers.ts +0 -141
  118. package/src/fix/runFix.ts +0 -96
  119. package/src/fix/unstage.ts +0 -25
  120. package/src/fix/utils.ts +0 -50
  121. package/src/git.ts +0 -17
  122. package/src/hook.ts +0 -98
  123. package/src/index.ts +0 -59
  124. package/src/reporter.ts +0 -88
  125. package/src/runScan.ts +0 -35
  126. package/src/scanner.ts +0 -44
  127. package/src/types.ts +0 -25
  128. package/test.ts +0 -6
  129. package/testing.ts +0 -3
  130. package/tsconfig.json +0 -44
package/dist/hook.js ADDED
@@ -0,0 +1,87 @@
1
+ import { execSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { CLI_NAME, PRODUCT_NAME } from "./brand.js";
5
+ const HOOK_MARKER = "# Generated by Commit Cop";
6
+ const BACKUP_SUFFIX = ".commit-cop.backup";
7
+ function getGitHooksDir() {
8
+ try {
9
+ const gitPath = execSync("git rev-parse --git-path hooks", {
10
+ encoding: "utf-8",
11
+ }).trim();
12
+ return path.resolve(gitPath);
13
+ }
14
+ catch {
15
+ throw new Error(`${PRODUCT_NAME} install must be run inside a Git repository.`);
16
+ }
17
+ }
18
+ function buildHookScript(strict) {
19
+ const strictFlag = strict ? " --strict" : "";
20
+ return `#!/bin/sh
21
+ ${HOOK_MARKER}
22
+ # Re-run: npx ${CLI_NAME} install
23
+
24
+ cd "$(git rev-parse --show-toplevel)" || exit 1
25
+
26
+ # Local development: run from source when working on Commit Cop itself
27
+ if [ -f package.json ] && [ -f src/index.ts ] && command -v npm >/dev/null 2>&1; then
28
+ exec npm run dev --${strictFlag}
29
+ fi
30
+
31
+ if [ -x "./node_modules/.bin/${CLI_NAME}" ]; then
32
+ exec ./node_modules/.bin/${CLI_NAME}${strictFlag}
33
+ fi
34
+
35
+ if command -v ${CLI_NAME} >/dev/null 2>&1; then
36
+ exec ${CLI_NAME}${strictFlag}
37
+ fi
38
+
39
+ exec npx ${CLI_NAME}${strictFlag}
40
+ `;
41
+ }
42
+ export function installHook(strict = false) {
43
+ const hooksDir = getGitHooksDir();
44
+ const hookPath = path.join(hooksDir, "pre-commit");
45
+ const backupPath = `${hookPath}${BACKUP_SUFFIX}`;
46
+ fs.mkdirSync(hooksDir, { recursive: true });
47
+ if (fs.existsSync(hookPath)) {
48
+ const existing = fs.readFileSync(hookPath, "utf-8");
49
+ if (existing.includes(HOOK_MARKER)) {
50
+ console.log(`${PRODUCT_NAME}: Updating existing pre-commit hook.`);
51
+ }
52
+ else {
53
+ fs.copyFileSync(hookPath, backupPath);
54
+ console.log(`${PRODUCT_NAME}: Backed up existing pre-commit hook to ${path.basename(backupPath)}.`);
55
+ }
56
+ }
57
+ fs.writeFileSync(hookPath, buildHookScript(strict), { mode: 0o755 });
58
+ console.log(`${PRODUCT_NAME}: Pre-commit hook installed.`);
59
+ console.log(` ${hookPath}`);
60
+ console.log("");
61
+ console.log("Commit Cop will now run automatically on git commit.");
62
+ if (strict) {
63
+ console.log("Strict mode is enabled for this hook.");
64
+ }
65
+ }
66
+ export function uninstallHook() {
67
+ const hooksDir = getGitHooksDir();
68
+ const hookPath = path.join(hooksDir, "pre-commit");
69
+ const backupPath = `${hookPath}${BACKUP_SUFFIX}`;
70
+ if (!fs.existsSync(hookPath)) {
71
+ console.log(`${PRODUCT_NAME}: No pre-commit hook found.`);
72
+ return;
73
+ }
74
+ const existing = fs.readFileSync(hookPath, "utf-8");
75
+ if (!existing.includes(HOOK_MARKER)) {
76
+ throw new Error(`${PRODUCT_NAME} did not install this pre-commit hook. Remove it manually if needed.`);
77
+ }
78
+ fs.unlinkSync(hookPath);
79
+ if (fs.existsSync(backupPath)) {
80
+ fs.copyFileSync(backupPath, hookPath);
81
+ fs.unlinkSync(backupPath);
82
+ console.log(`${PRODUCT_NAME}: Pre-commit hook removed and previous hook restored.`);
83
+ return;
84
+ }
85
+ console.log(`${PRODUCT_NAME}: Pre-commit hook removed.`);
86
+ }
87
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,30 +1,47 @@
1
1
  #!/usr/bin/env node
2
+ import { CLI_NAME, PRODUCT_NAME, TAGLINE } from "./brand.js";
2
3
  import { Command } from "commander";
3
- import { getStagedFiles } from "./git.js";
4
- import { runChecks } from "./scanner.js";
5
- import { printReport } from "./reporter.js";
4
+ import { runWipFix } from "./fix/runFix.js";
5
+ import { installHook, uninstallHook } from "./hook.js";
6
+ import { runScan } from "./runScan.js";
6
7
  const program = new Command();
7
8
  program
8
- .name("commit-cop")
9
- .description("Pre-commit safety checker for staged files")
9
+ .name(CLI_NAME)
10
+ .description(`${PRODUCT_NAME} ${TAGLINE}`);
11
+ program
12
+ .command("scan", { isDefault: true })
13
+ .description("Scan staged files for risky commits")
10
14
  .option("--strict", "Treat warnings as errors")
15
+ .option("--allow-console-log", "Skip console.log warnings (for projects that keep console.log on purpose)")
11
16
  .action(async (options) => {
12
- const stagedFiles = getStagedFiles();
13
- if (stagedFiles.length === 0) {
14
- console.log("No staged files found.");
15
- return;
16
- }
17
- const findings = await runChecks({
18
- stagedFiles,
19
- strict: Boolean(options.strict),
20
- });
21
- printReport(findings, stagedFiles.length);
22
- const hasErrors = findings.some((finding) => finding.severity === "error");
23
- const hasWarnings = findings.some((finding) => finding.severity === "warning");
24
- if (hasErrors || (options.strict && hasWarnings)) {
25
- process.exit(1);
26
- }
27
- process.exit(0);
17
+ const exitCode = await runScan(Boolean(options.strict), Boolean(options.allowConsoleLog));
18
+ process.exit(exitCode);
19
+ });
20
+ program
21
+ .command("wip-fix")
22
+ .description("Apply common repo fixes matching commit-cop checks (.gitignore, debug code, unstaging, etc.)")
23
+ .option("--fix-console-log", "Also remove standalone console.log lines from staged files (debugger lines are always removed)")
24
+ .action((options) => {
25
+ runWipFix({ fixConsoleLog: Boolean(options.fixConsoleLog) });
26
+ });
27
+ program
28
+ .command("install")
29
+ .description("Install a Git pre-commit hook that runs Commit Cop on every commit")
30
+ .option("--strict", "Treat warnings as errors in the hook")
31
+ .action((options) => {
32
+ installHook(Boolean(options.strict));
33
+ });
34
+ program
35
+ .command("uninstall")
36
+ .description("Remove the Commit Cop pre-commit hook")
37
+ .action(() => {
38
+ uninstallHook();
39
+ });
40
+ program
41
+ .command("wip-fix")
42
+ .description("Apply common repo fixes (work in progress)")
43
+ .action(() => {
44
+ runWipFix();
28
45
  });
29
46
  program.parse();
30
47
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,4CAA4C,CAAC;KACzD,MAAM,CAAC,UAAU,EAAE,0BAA0B,CAAC;KAC9C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACtC,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC;QAC/B,WAAW;QACX,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;KAChC,CAAC,CAAC;IAEH,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAE1C,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC3E,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAC/B,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAC5C,CAAC;IAEF,IAAI,SAAS,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,WAAW,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,GAAG,YAAY,MAAM,OAAO,EAAE,CAAC,CAAC;AAE/C,OAAO;KACJ,OAAO,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACpC,WAAW,CAAC,qCAAqC,CAAC;KAClD,MAAM,CAAC,UAAU,EAAE,0BAA0B,CAAC;KAC9C,MAAM,CACL,qBAAqB,EACrB,2EAA2E,CAC5E;KACA,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAC5B,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EACvB,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CACjC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACzB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CACV,8FAA8F,CAC/F;KACA,MAAM,CACL,mBAAmB,EACnB,gGAAgG,CACjG;KACA,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;IAClB,SAAS,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,oEAAoE,CAAC;KACjF,MAAM,CAAC,UAAU,EAAE,sCAAsC,CAAC;KAC1D,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;IAClB,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,uCAAuC,CAAC;KACpD,MAAM,CAAC,GAAG,EAAE;IACX,aAAa,EAAE,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,4CAA4C,CAAC;KACzD,MAAM,CAAC,GAAG,EAAE;IACX,SAAS,EAAE,CAAC;AACd,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import type { Finding } from "./types.js";
2
- export declare function printReport(findings: Finding[], scannedCount: number): void;
2
+ export declare function printReport(findings: Finding[], scannedCount: number, strict: boolean): number;
3
3
  //# sourceMappingURL=reporter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,QA+BpE"}
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA4G1C,wBAAgB,WAAW,CACzB,QAAQ,EAAE,OAAO,EAAE,EACnB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,OAAO,GACd,MAAM,CA2BR"}
package/dist/reporter.js CHANGED
@@ -1,38 +1,96 @@
1
+ import { PRODUCT_NAME } from "./brand.js";
1
2
  import chalk from "chalk";
2
- export function printReport(findings, scannedCount) {
3
- console.log(chalk.bold("\nCommitClean Report\n"));
4
- console.log(`Scanned ${scannedCount} staged file(s).\n`);
5
- const errors = findings.filter((f) => f.severity === "error");
6
- const warnings = findings.filter((f) => f.severity === "warning");
7
- console.log(chalk.red(`Errors: ${errors.length}`));
8
- console.log(chalk.yellow(`Warnings: ${warnings.length}`));
9
- console.log("");
10
- if (findings.length === 0) {
11
- console.log(chalk.green("✅ No issues found. Commit looks clean.\n"));
12
- return;
13
- }
14
- if (errors.length > 0) {
15
- console.log(chalk.red.bold("❌ Errors"));
16
- for (const finding of errors) {
17
- printFinding(finding);
18
- }
19
- }
20
- if (warnings.length > 0) {
21
- console.log(chalk.yellow.bold("\n⚠️ Warnings"));
22
- for (const finding of warnings) {
23
- printFinding(finding);
24
- }
25
- }
3
+ const WIDTH = 52;
4
+ function line(char = "─") {
5
+ return chalk.dim(char.repeat(WIDTH));
6
+ }
7
+ function printHeader(title) {
8
+ console.log("");
9
+ console.log(line("═"));
10
+ console.log(chalk.bold(` ${title}`));
11
+ console.log(line("═"));
12
+ }
13
+ function printSection(title, color) {
14
+ console.log("");
15
+ console.log(line());
16
+ console.log(color(chalk.bold(` ${title}`)));
17
+ console.log(line());
26
18
  console.log("");
27
19
  }
28
- function printFinding(finding) {
20
+ function printFinding(finding, index) {
29
21
  const location = finding.line
30
22
  ? `${finding.file}:${finding.line}`
31
23
  : finding.file;
32
- console.log(`- ${chalk.bold(location)}`);
33
- console.log(` ${finding.message}`);
24
+ const checkLabel = chalk.dim(`[${finding.checkName}]`);
25
+ console.log(chalk.bold(` ${index}.`) + ` ${checkLabel}`);
26
+ console.log(` ${chalk.cyan(location)}`);
27
+ console.log(` ${finding.message}`);
34
28
  if (finding.suggestion) {
35
- console.log(chalk.gray(` Fix: ${finding.suggestion}`));
29
+ console.log(chalk.gray(` ${finding.suggestion}`));
30
+ }
31
+ console.log("");
32
+ }
33
+ function printFindings(findings, severity) {
34
+ const filtered = findings.filter((finding) => finding.severity === severity);
35
+ filtered.forEach((finding, index) => {
36
+ printFinding(finding, index + 1);
37
+ });
38
+ }
39
+ function printSummary(strict, errorCount, warningCount) {
40
+ console.log("");
41
+ console.log(`Strict Mode: ${strict ? "ON" : "OFF"}`);
42
+ console.log(` ${chalk.red(`Errors: ${errorCount}`)}${chalk.dim(" │ ")}${chalk.yellow(`Warnings: ${warningCount}`)}`);
43
+ console.log("");
44
+ }
45
+ function colorErrors(text) {
46
+ return text.replace(/\berrors\b/gi, (match) => chalk.red(match));
47
+ }
48
+ function colorWarnings(text) {
49
+ return text.replace(/\bwarnings\b/gi, (match) => chalk.yellow(match));
50
+ }
51
+ function colorOutcomeMessage(text) {
52
+ return colorErrors(colorWarnings(text));
53
+ }
54
+ function resolveOutcome(strict, errorCount, warningCount) {
55
+ if (errorCount > 0) {
56
+ console.error(colorOutcomeMessage(`${PRODUCT_NAME} found errors.`));
57
+ console.error(colorOutcomeMessage("Please fix the errors before committing successfully."));
58
+ return 1;
59
+ }
60
+ if (strict && warningCount > 0) {
61
+ console.error(colorOutcomeMessage(`${PRODUCT_NAME} found warnings.`));
62
+ console.error(colorOutcomeMessage("Please fix the warnings before committing successfully."));
63
+ return 1;
36
64
  }
65
+ if (!strict && warningCount > 0) {
66
+ console.warn(colorOutcomeMessage(`${PRODUCT_NAME} found warnings, but no errors.`));
67
+ console.warn(`Your commit was ${chalk.green("successful")}.`);
68
+ console.warn(colorOutcomeMessage(`If you still like to clean up these ${chalk.yellow("warnings")}, review these before commiting again.`));
69
+ return 0;
70
+ }
71
+ console.log(`${PRODUCT_NAME} passed.`);
72
+ console.log(colorOutcomeMessage("No errors or warnings found."));
73
+ console.log(`Your commit was ${chalk.green("successful")}.`);
74
+ return 0;
75
+ }
76
+ export function printReport(findings, scannedCount, strict) {
77
+ const errorCount = findings.filter((finding) => finding.severity === "error").length;
78
+ const warningCount = findings.filter((finding) => finding.severity === "warning").length;
79
+ printHeader(`${PRODUCT_NAME} Report`);
80
+ console.log("");
81
+ console.log(chalk.dim(` Scanned ${scannedCount} staged file(s)`));
82
+ printSummary(strict, errorCount, warningCount);
83
+ if (errorCount > 0) {
84
+ printSection(`ERRORS (${errorCount})`, chalk.red);
85
+ printFindings(findings, "error");
86
+ }
87
+ if (warningCount > 0) {
88
+ printSection(`WARNINGS (${warningCount})`, chalk.yellow);
89
+ printFindings(findings, "warning");
90
+ }
91
+ const exitCode = resolveOutcome(strict, errorCount, warningCount);
92
+ console.log(line("═"));
93
+ console.log("");
94
+ return exitCode;
37
95
  }
38
96
  //# sourceMappingURL=reporter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,UAAU,WAAW,CAAC,QAAmB,EAAE,YAAoB;IACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,WAAW,YAAY,oBAAoB,CAAC,CAAC;IAEzD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACxC,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;YAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;QAChD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,YAAY,CAAC,OAAgB;IACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI;QAC3B,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE;QACnC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAEjB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAEpC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runScan(strict?: boolean, allowConsoleLog?: boolean): Promise<number>;
2
+ //# sourceMappingURL=runScan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runScan.d.ts","sourceRoot":"","sources":["../src/runScan.ts"],"names":[],"mappings":"AAKA,wBAAsB,OAAO,CAC3B,MAAM,UAAQ,EACd,eAAe,UAAQ,GACtB,OAAO,CAAC,MAAM,CAAC,CAejB"}
@@ -0,0 +1,18 @@
1
+ import { PRODUCT_NAME } from "./brand.js";
2
+ import { getStagedFiles } from "./git.js";
3
+ import { runChecks } from "./scanner.js";
4
+ import { printReport } from "./reporter.js";
5
+ export async function runScan(strict = false, allowConsoleLog = false) {
6
+ const stagedFiles = getStagedFiles();
7
+ if (stagedFiles.length === 0) {
8
+ console.log(`${PRODUCT_NAME}: No staged files found.`);
9
+ return 0;
10
+ }
11
+ const findings = await runChecks({
12
+ stagedFiles,
13
+ strict,
14
+ allowConsoleLog,
15
+ });
16
+ return printReport(findings, stagedFiles.length, strict);
17
+ }
18
+ //# sourceMappingURL=runScan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runScan.js","sourceRoot":"","sources":["../src/runScan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAM,GAAG,KAAK,EACd,eAAe,GAAG,KAAK;IAEvB,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,YAAY,0BAA0B,CAAC,CAAC;QACvD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC;QAC/B,WAAW;QACX,MAAM;QACN,eAAe;KAChB,CAAC,CAAC;IAEH,OAAO,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC3D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA+BxD,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CASzE"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA+BxD,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAYzE"}
package/dist/scanner.js CHANGED
@@ -28,7 +28,10 @@ const checks = [
28
28
  ];
29
29
  export async function runChecks(context) {
30
30
  const allFindings = [];
31
- for (const check of checks) {
31
+ const activeChecks = context.allowConsoleLog
32
+ ? checks.filter((check) => check !== consoleLogCheck)
33
+ : checks;
34
+ for (const check of activeChecks) {
32
35
  const findings = await check.run(context);
33
36
  allFindings.push(...findings);
34
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,MAAM,GAAG;IACb,kBAAkB;IAClB,YAAY;IACZ,sBAAsB;IACtB,oBAAoB;IACpB,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,aAAa;IACb,cAAc;IACd,aAAa;IACb,kBAAkB;IAClB,cAAc;IACd,eAAe;CAChB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAqB;IACnD,MAAM,WAAW,GAAc,EAAE,CAAC;IAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1C,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,MAAM,GAAG;IACb,kBAAkB;IAClB,YAAY;IACZ,sBAAsB;IACtB,oBAAoB;IACpB,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,aAAa;IACb,cAAc;IACd,aAAa;IACb,kBAAkB;IAClB,cAAc;IACd,eAAe;CAChB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAqB;IACnD,MAAM,WAAW,GAAc,EAAE,CAAC;IAClC,MAAM,YAAY,GAAG,OAAO,CAAC,eAAe;QAC1C,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,eAAe,CAAC;QACrD,CAAC,CAAC,MAAM,CAAC;IAEX,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1C,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
package/dist/types.d.ts CHANGED
@@ -10,6 +10,10 @@ export type Finding = {
10
10
  export type CheckContext = {
11
11
  stagedFiles: string[];
12
12
  strict: boolean;
13
+ allowConsoleLog?: boolean;
14
+ };
15
+ export type WipFixOptions = {
16
+ fixConsoleLog?: boolean;
13
17
  };
14
18
  export type Check = {
15
19
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACpD,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACpD,CAAC"}
package/package.json CHANGED
@@ -1,14 +1,18 @@
1
1
  {
2
2
  "name": "commit-cop",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Commit Cop — a pre-commit safety checker that scans staged files for risky commits.",
5
5
  "type": "module",
6
+ "files": [
7
+ "dist"
8
+ ],
6
9
  "bin": {
7
10
  "commit-cop": "./dist/index.js"
8
11
  },
9
12
  "scripts": {
10
13
  "dev": "tsx src/index.ts",
11
14
  "build": "tsc",
15
+ "prepublishOnly": "npm run build",
12
16
  "start": "node dist/index.js",
13
17
  "commit-cop": "tsx src/index.ts",
14
18
  "demo:setup": "node scripts/setup-demo.mjs"
@@ -37,6 +41,7 @@
37
41
  },
38
42
  "dependencies": {
39
43
  "chalk": "^5.6.2",
40
- "commander": "^14.0.3"
44
+ "commander": "^14.0.3",
45
+ "commit-cop": "^1.0.1"
41
46
  }
42
47
  }
@@ -1,64 +0,0 @@
1
- import fs from "node:fs";
2
- import type { Check, Finding } from "../types.js";
3
- import { getBaseName } from "./utils.js";
4
-
5
- const binaryExtensions = new Set([
6
- ".zip",
7
- ".exe",
8
- ".dll",
9
- ".mp4",
10
- ".mov",
11
- ".sqlite",
12
- ".db",
13
- ]);
14
-
15
- function hasNullBytes(file: string): boolean {
16
- const buffer = fs.readFileSync(file);
17
- const sampleSize = Math.min(buffer.length, 8192);
18
-
19
- for (let index = 0; index < sampleSize; index += 1) {
20
- if (buffer[index] === 0) {
21
- return true;
22
- }
23
- }
24
-
25
- return false;
26
- }
27
-
28
- export const binaryFileCheck: Check = {
29
- name: "binary-file-check",
30
-
31
- async run(context) {
32
- const findings: Finding[] = [];
33
-
34
- for (const file of context.stagedFiles) {
35
- if (!fs.existsSync(file)) continue;
36
-
37
- const baseName = getBaseName(file);
38
- const extension = baseName.includes(".")
39
- ? baseName.slice(baseName.lastIndexOf(".")).toLowerCase()
40
- : "";
41
-
42
- let isBinary = binaryExtensions.has(extension);
43
-
44
- try {
45
- isBinary ||= hasNullBytes(file);
46
- } catch {
47
- continue;
48
- }
49
-
50
- if (isBinary) {
51
- findings.push({
52
- severity: "warning",
53
- checkName: this.name,
54
- file,
55
- message:
56
- "Binary file detected — archives, executables, and media don't belong in source control.",
57
- suggestion: "Remove it from the commit or store it with Git LFS.",
58
- });
59
- }
60
- }
61
-
62
- return findings;
63
- },
64
- };
@@ -1,40 +0,0 @@
1
- import fs from "node:fs";
2
- import type { Check, Finding } from "../types.js";
3
-
4
- const codeExtensions = [".js", ".jsx", ".ts", ".tsx"];
5
-
6
- function isCodeFile(file: string): boolean {
7
- return codeExtensions.some((ext) => file.endsWith(ext));
8
- }
9
-
10
- export const consoleLogCheck: Check = {
11
- name: "console-log-check",
12
-
13
- async run(context) {
14
- const findings: Finding[] = [];
15
-
16
- for (const file of context.stagedFiles) {
17
- if (!isCodeFile(file)) continue;
18
- if (!fs.existsSync(file)) continue;
19
-
20
- const content = fs.readFileSync(file, "utf-8");
21
- const lines = content.split("\n");
22
-
23
- lines.forEach((line, index) => {
24
- if (line.includes("console.log")) {
25
- findings.push({
26
- severity: "warning",
27
- checkName: this.name,
28
- file,
29
- line: index + 1,
30
- message:
31
- "Debug log left in code — easy to miss and clutters production output.",
32
- suggestion: "Delete the console.log before committing.",
33
- });
34
- }
35
- });
36
- }
37
-
38
- return findings;
39
- },
40
- };
@@ -1,33 +0,0 @@
1
- import type { Check, Finding } from "../types.js";
2
- import { isCodeFile, readFileLines } from "./utils.js";
3
-
4
- export const debuggerCheck: Check = {
5
- name: "debugger-check",
6
-
7
- async run(context) {
8
- const findings: Finding[] = [];
9
-
10
- for (const file of context.stagedFiles) {
11
- if (!isCodeFile(file)) continue;
12
-
13
- const lines = readFileLines(file);
14
- if (!lines) continue;
15
-
16
- lines.forEach((line, index) => {
17
- if (/\bdebugger\b/.test(line)) {
18
- findings.push({
19
- severity: "warning",
20
- checkName: this.name,
21
- file,
22
- line: index + 1,
23
- message:
24
- "debugger statement left in code — pauses execution and breaks CI/headless runs.",
25
- suggestion: "Delete the debugger statement before committing.",
26
- });
27
- }
28
- });
29
- }
30
-
31
- return findings;
32
- },
33
- };
@@ -1,26 +0,0 @@
1
- import type { Check, Finding } from "../types.js";
2
-
3
- export const envFileCheck: Check = {
4
- name: "env-file-check",
5
-
6
- async run(context) {
7
- const findings: Finding[] = [];
8
-
9
- for (const file of context.stagedFiles) {
10
- const fileName = file.split("/").pop() ?? "";
11
-
12
- if (fileName === ".env" || fileName.startsWith(".env.")) {
13
- findings.push({
14
- severity: "error",
15
- checkName: this.name,
16
- file,
17
- message:
18
- ".env file detected — these often hold API keys, passwords, and tokens.",
19
- suggestion: `Unstage it: git restore --staged ${file}`,
20
- });
21
- }
22
- }
23
-
24
- return findings;
25
- },
26
- };