commit-cop 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -7
- package/dist/brand.d.ts +4 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +4 -0
- package/dist/brand.js.map +1 -0
- package/dist/checks/binaryFileCheck.js +2 -2
- package/dist/checks/binaryFileCheck.js.map +1 -1
- package/dist/checks/consoleLogCheck.d.ts.map +1 -1
- package/dist/checks/consoleLogCheck.js +2 -2
- package/dist/checks/consoleLogCheck.js.map +1 -1
- package/dist/checks/debuggerCheck.d.ts.map +1 -1
- package/dist/checks/debuggerCheck.js +2 -2
- package/dist/checks/debuggerCheck.js.map +1 -1
- package/dist/checks/envFileCheck.d.ts.map +1 -1
- package/dist/checks/envFileCheck.js +2 -2
- package/dist/checks/envFileCheck.js.map +1 -1
- package/dist/checks/focusedTestCheck.js +2 -2
- package/dist/checks/focusedTestCheck.js.map +1 -1
- package/dist/checks/generatedFolderCheck.js +2 -2
- package/dist/checks/generatedFolderCheck.js.map +1 -1
- package/dist/checks/junkFileCheck.d.ts.map +1 -1
- package/dist/checks/junkFileCheck.js +2 -2
- package/dist/checks/junkFileCheck.js.map +1 -1
- package/dist/checks/largeFileCheck.js +2 -2
- package/dist/checks/largeFileCheck.js.map +1 -1
- package/dist/checks/localHostCheck.js +2 -2
- package/dist/checks/localHostCheck.js.map +1 -1
- package/dist/checks/lockfileDriftCheck.d.ts.map +1 -1
- package/dist/checks/lockfileDriftCheck.js +4 -4
- package/dist/checks/lockfileDriftCheck.js.map +1 -1
- package/dist/checks/mergeConflictCheck.d.ts.map +1 -1
- package/dist/checks/mergeConflictCheck.js +2 -2
- package/dist/checks/mergeConflictCheck.js.map +1 -1
- package/dist/checks/secretCheck.js +19 -19
- package/dist/checks/secretCheck.js.map +1 -1
- package/dist/checks/sensitiveFilenameCheck.d.ts.map +1 -1
- package/dist/checks/sensitiveFilenameCheck.js +2 -2
- package/dist/checks/sensitiveFilenameCheck.js.map +1 -1
- package/dist/fix/debugCode.d.ts +3 -0
- package/dist/fix/debugCode.d.ts.map +1 -0
- package/dist/fix/debugCode.js +55 -0
- package/dist/fix/debugCode.js.map +1 -0
- package/dist/fix/focusedTests.d.ts +2 -0
- package/dist/fix/focusedTests.d.ts.map +1 -0
- package/dist/fix/focusedTests.js +22 -0
- package/dist/fix/focusedTests.js.map +1 -0
- package/dist/fix/gitignore.d.ts +2 -0
- package/dist/fix/gitignore.d.ts.map +1 -0
- package/dist/fix/gitignore.js +82 -0
- package/dist/fix/gitignore.js.map +1 -0
- package/dist/fix/junkFiles.d.ts +2 -0
- package/dist/fix/junkFiles.d.ts.map +1 -0
- package/dist/fix/junkFiles.js +14 -0
- package/dist/fix/junkFiles.js.map +1 -0
- package/dist/fix/lockfile.d.ts +2 -0
- package/dist/fix/lockfile.d.ts.map +1 -0
- package/dist/fix/lockfile.js +18 -0
- package/dist/fix/lockfile.js.map +1 -0
- package/dist/fix/matchers.d.ts +9 -0
- package/dist/fix/matchers.d.ts.map +1 -0
- package/dist/fix/matchers.js +118 -0
- package/dist/fix/matchers.js.map +1 -0
- package/dist/fix/runFix.d.ts +3 -0
- package/dist/fix/runFix.d.ts.map +1 -0
- package/dist/fix/runFix.js +82 -0
- package/dist/fix/runFix.js.map +1 -0
- package/dist/fix/unstage.d.ts +2 -0
- package/dist/fix/unstage.d.ts.map +1 -0
- package/dist/fix/unstage.js +22 -0
- package/dist/fix/unstage.js.map +1 -0
- package/dist/fix/utils.d.ts +4 -0
- package/dist/fix/utils.d.ts.map +1 -0
- package/dist/fix/utils.js +39 -0
- package/dist/fix/utils.js.map +1 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +2 -1
- package/dist/git.js.map +1 -1
- package/dist/hook.d.ts +3 -0
- package/dist/hook.d.ts.map +1 -0
- package/dist/hook.js +79 -0
- package/dist/hook.js.map +1 -0
- package/dist/index.js +32 -21
- package/dist/index.js.map +1 -1
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +56 -26
- package/dist/reporter.js.map +1 -1
- package/dist/runScan.d.ts +2 -0
- package/dist/runScan.d.ts.map +1 -0
- package/dist/runScan.js +24 -0
- package/dist/runScan.js.map +1 -0
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +4 -1
- package/dist/scanner.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/brand.ts +3 -0
- package/src/checks/binaryFileCheck.ts +3 -3
- package/src/checks/consoleLogCheck.ts +3 -2
- package/src/checks/debuggerCheck.ts +3 -2
- package/src/checks/envFileCheck.ts +3 -2
- package/src/checks/focusedTestCheck.ts +2 -2
- package/src/checks/generatedFolderCheck.ts +2 -2
- package/src/checks/junkFileCheck.ts +3 -2
- package/src/checks/largeFileCheck.ts +2 -2
- package/src/checks/localHostCheck.ts +2 -2
- package/src/checks/lockfileDriftCheck.ts +6 -4
- package/src/checks/mergeConflictCheck.ts +3 -2
- package/src/checks/secretCheck.ts +19 -19
- package/src/checks/sensitiveFilenameCheck.ts +3 -2
- package/src/fix/debugCode.ts +74 -0
- package/src/fix/focusedTests.ts +26 -0
- package/src/fix/gitignore.ts +108 -0
- package/src/fix/junkFiles.ts +16 -0
- package/src/fix/lockfile.ts +23 -0
- package/src/fix/matchers.ts +141 -0
- package/src/fix/runFix.ts +96 -0
- package/src/fix/unstage.ts +25 -0
- package/src/fix/utils.ts +50 -0
- package/src/git.ts +2 -1
- package/src/hook.ts +98 -0
- package/src/index.ts +45 -27
- package/src/reporter.ts +70 -30
- package/src/runScan.ts +35 -0
- package/src/scanner.ts +4 -1
- package/src/types.ts +5 -0
- package/test.ts +5 -1
- package/testing.ts +3 -0
package/dist/index.js
CHANGED
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { CLI_NAME, PRODUCT_NAME, TAGLINE } from "./brand.js";
|
|
2
3
|
import { Command } from "commander";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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(
|
|
9
|
-
.description(
|
|
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
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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();
|
|
28
39
|
});
|
|
29
40
|
program.parse();
|
|
30
41
|
//# 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,
|
|
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,CAAC,KAAK,EAAE,CAAC"}
|
package/dist/reporter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAY,MAAM,YAAY,CAAC;AAyDpD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,QA4BpE"}
|
package/dist/reporter.js
CHANGED
|
@@ -1,38 +1,68 @@
|
|
|
1
|
+
import { PRODUCT_NAME } from "./brand.js";
|
|
1
2
|
import chalk from "chalk";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
console.log(
|
|
8
|
-
console.log(
|
|
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());
|
|
18
|
+
console.log("");
|
|
19
|
+
}
|
|
20
|
+
function printSummary(scannedCount, errors, warnings) {
|
|
9
21
|
console.log("");
|
|
22
|
+
console.log(chalk.dim(` Scanned ${scannedCount} staged file(s)`));
|
|
23
|
+
console.log(` ${chalk.red(`Errors: ${errors}`)}${chalk.dim(" │ ")}${chalk.yellow(`Warnings: ${warnings}`)}`);
|
|
24
|
+
}
|
|
25
|
+
function printFinding(finding, index) {
|
|
26
|
+
const location = finding.line
|
|
27
|
+
? `${finding.file}:${finding.line}`
|
|
28
|
+
: finding.file;
|
|
29
|
+
const checkLabel = chalk.dim(`[${finding.checkName}]`);
|
|
30
|
+
console.log(chalk.bold(` ${index}.`) + ` ${checkLabel}`);
|
|
31
|
+
console.log(` ${chalk.cyan(location)}`);
|
|
32
|
+
console.log(` ${finding.message}`);
|
|
33
|
+
if (finding.suggestion) {
|
|
34
|
+
console.log(chalk.gray(` → ${finding.suggestion}`));
|
|
35
|
+
}
|
|
36
|
+
console.log("");
|
|
37
|
+
}
|
|
38
|
+
function printFindings(findings, severity) {
|
|
39
|
+
const filtered = findings.filter((finding) => finding.severity === severity);
|
|
40
|
+
filtered.forEach((finding, index) => {
|
|
41
|
+
printFinding(finding, index + 1);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export function printReport(findings, scannedCount) {
|
|
45
|
+
const errors = findings.filter((finding) => finding.severity === "error");
|
|
46
|
+
const warnings = findings.filter((finding) => finding.severity === "warning");
|
|
47
|
+
printHeader(`${PRODUCT_NAME} Report`);
|
|
48
|
+
printSummary(scannedCount, errors.length, warnings.length);
|
|
10
49
|
if (findings.length === 0) {
|
|
11
|
-
console.log(
|
|
50
|
+
console.log("");
|
|
51
|
+
console.log(chalk.green(" ✅ All clear — no issues found in staged files."));
|
|
52
|
+
console.log("");
|
|
53
|
+
console.log(line("═"));
|
|
54
|
+
console.log("");
|
|
12
55
|
return;
|
|
13
56
|
}
|
|
14
57
|
if (errors.length > 0) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
printFinding(finding);
|
|
18
|
-
}
|
|
58
|
+
printSection(`ERRORS (${errors.length})`, chalk.red);
|
|
59
|
+
printFindings(findings, "error");
|
|
19
60
|
}
|
|
20
61
|
if (warnings.length > 0) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
printFinding(finding);
|
|
24
|
-
}
|
|
62
|
+
printSection(`WARNINGS (${warnings.length})`, chalk.yellow);
|
|
63
|
+
printFindings(findings, "warning");
|
|
25
64
|
}
|
|
65
|
+
console.log(line("═"));
|
|
26
66
|
console.log("");
|
|
27
67
|
}
|
|
28
|
-
function printFinding(finding) {
|
|
29
|
-
const location = finding.line
|
|
30
|
-
? `${finding.file}:${finding.line}`
|
|
31
|
-
: finding.file;
|
|
32
|
-
console.log(`- ${chalk.bold(location)}`);
|
|
33
|
-
console.log(` ${finding.message}`);
|
|
34
|
-
if (finding.suggestion) {
|
|
35
|
-
console.log(chalk.gray(` Fix: ${finding.suggestion}`));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
68
|
//# sourceMappingURL=reporter.js.map
|
package/dist/reporter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,CA0BjB"}
|
package/dist/runScan.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
printReport(findings, stagedFiles.length);
|
|
17
|
+
const hasErrors = findings.some((finding) => finding.severity === "error");
|
|
18
|
+
const hasWarnings = findings.some((finding) => finding.severity === "warning");
|
|
19
|
+
if (hasErrors || (strict && hasWarnings)) {
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
//# 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,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,MAAM,IAAI,WAAW,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC"}
|
package/dist/scanner.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
}
|
package/dist/scanner.js.map
CHANGED
|
@@ -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;
|
|
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
package/dist/types.d.ts.map
CHANGED
|
@@ -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;
|
|
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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "commit-cop",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "Commit Cop — a pre-commit safety checker that scans staged files for risky commits.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"commit-cop": "./dist/index.js"
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"dev": "tsx src/index.ts",
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"start": "node dist/index.js",
|
|
13
|
-
"commit-cop": "tsx src/index.ts"
|
|
13
|
+
"commit-cop": "tsx src/index.ts",
|
|
14
|
+
"demo:setup": "node scripts/setup-demo.mjs"
|
|
14
15
|
},
|
|
15
16
|
"repository": {
|
|
16
17
|
"type": "git",
|
package/src/brand.ts
ADDED
|
@@ -52,9 +52,9 @@ export const binaryFileCheck: Check = {
|
|
|
52
52
|
severity: "warning",
|
|
53
53
|
checkName: this.name,
|
|
54
54
|
file,
|
|
55
|
-
message:
|
|
56
|
-
|
|
57
|
-
|
|
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
58
|
});
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -27,8 +27,9 @@ export const consoleLogCheck: Check = {
|
|
|
27
27
|
checkName: this.name,
|
|
28
28
|
file,
|
|
29
29
|
line: index + 1,
|
|
30
|
-
message:
|
|
31
|
-
|
|
30
|
+
message:
|
|
31
|
+
"Debug log left in code — easy to miss and clutters production output.",
|
|
32
|
+
suggestion: "Delete the console.log before committing.",
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
});
|
|
@@ -20,8 +20,9 @@ export const debuggerCheck: Check = {
|
|
|
20
20
|
checkName: this.name,
|
|
21
21
|
file,
|
|
22
22
|
line: index + 1,
|
|
23
|
-
message:
|
|
24
|
-
|
|
23
|
+
message:
|
|
24
|
+
"debugger statement left in code — pauses execution and breaks CI/headless runs.",
|
|
25
|
+
suggestion: "Delete the debugger statement before committing.",
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
});
|
|
@@ -14,8 +14,9 @@ export const envFileCheck: Check = {
|
|
|
14
14
|
severity: "error",
|
|
15
15
|
checkName: this.name,
|
|
16
16
|
file,
|
|
17
|
-
message:
|
|
18
|
-
|
|
17
|
+
message:
|
|
18
|
+
".env file detected — these often hold API keys, passwords, and tokens.",
|
|
19
|
+
suggestion: `Unstage it: git restore --staged ${file}`,
|
|
19
20
|
});
|
|
20
21
|
}
|
|
21
22
|
}
|
|
@@ -28,8 +28,8 @@ export const focusedTestCheck: Check = {
|
|
|
28
28
|
checkName: this.name,
|
|
29
29
|
file,
|
|
30
30
|
line: index + 1,
|
|
31
|
-
message: `${pattern}
|
|
32
|
-
suggestion: `
|
|
31
|
+
message: `${pattern} detected — only that test will run, hiding failures in the rest of the suite.`,
|
|
32
|
+
suggestion: `Change ${pattern} back to ${pattern.replace(".only", "")}.`,
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -34,8 +34,8 @@ export const generatedFolderCheck: Check = {
|
|
|
34
34
|
severity: "error",
|
|
35
35
|
checkName: this.name,
|
|
36
36
|
file,
|
|
37
|
-
message:
|
|
38
|
-
suggestion: `Add ${matchedFolder} to .gitignore
|
|
37
|
+
message: `Generated folder (${matchedFolder}) — auto-built files bloat the repo and cause merge pain.`,
|
|
38
|
+
suggestion: `Add ${matchedFolder} to .gitignore, then: git restore --staged ${file}`,
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -28,8 +28,9 @@ export const junkFileCheck: Check = {
|
|
|
28
28
|
severity: "warning",
|
|
29
29
|
checkName: this.name,
|
|
30
30
|
file,
|
|
31
|
-
message:
|
|
32
|
-
|
|
31
|
+
message:
|
|
32
|
+
"OS or editor junk file — adds noise and has no place in the repo.",
|
|
33
|
+
suggestion: `Unstage it: git restore --staged ${file}`,
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -20,8 +20,8 @@ export const largeFileCheck: Check = {
|
|
|
20
20
|
severity: "warning",
|
|
21
21
|
checkName: this.name,
|
|
22
22
|
file,
|
|
23
|
-
message: `Large file
|
|
24
|
-
suggestion: "
|
|
23
|
+
message: `Large file (${sizeMb.toFixed(2)} MB) — slows clones and may hit GitHub's size limits.`,
|
|
24
|
+
suggestion: "Remove it from Git or use Git LFS for big assets.",
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -27,8 +27,8 @@ export const localHostCheck: Check = {
|
|
|
27
27
|
checkName: this.name,
|
|
28
28
|
file,
|
|
29
29
|
line: index + 1,
|
|
30
|
-
message: `Hardcoded local URL
|
|
31
|
-
suggestion: "
|
|
30
|
+
message: `Hardcoded local URL (${pattern}) — won't work in production or for teammates.`,
|
|
31
|
+
suggestion: "Move the URL to an environment variable (e.g. process.env.API_URL).",
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -18,8 +18,9 @@ export const lockfileDriftCheck: Check = {
|
|
|
18
18
|
severity: "warning",
|
|
19
19
|
checkName: this.name,
|
|
20
20
|
file: "package.json",
|
|
21
|
-
message:
|
|
22
|
-
|
|
21
|
+
message:
|
|
22
|
+
"package.json changed without its lockfile — teammates may get different dependency versions.",
|
|
23
|
+
suggestion: "Run npm install, then stage package-lock.json.",
|
|
23
24
|
});
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -28,8 +29,9 @@ export const lockfileDriftCheck: Check = {
|
|
|
28
29
|
severity: "warning",
|
|
29
30
|
checkName: this.name,
|
|
30
31
|
file: "package-lock.json",
|
|
31
|
-
message:
|
|
32
|
-
|
|
32
|
+
message:
|
|
33
|
+
"Lockfile changed without package.json — the lockfile may not match your declared dependencies.",
|
|
34
|
+
suggestion: "Stage package.json too, or unstage package-lock.json.",
|
|
33
35
|
});
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -25,9 +25,10 @@ export const mergeConflictCheck: Check = {
|
|
|
25
25
|
checkName: this.name,
|
|
26
26
|
file,
|
|
27
27
|
line: index + 1,
|
|
28
|
-
message:
|
|
28
|
+
message:
|
|
29
|
+
"Unresolved merge conflict — this file won't run correctly until fixed.",
|
|
29
30
|
suggestion:
|
|
30
|
-
"Resolve the conflict, remove the markers,
|
|
31
|
+
"Resolve the conflict, remove the <<<<<<< / ======= / >>>>>>> markers, then restage.",
|
|
31
32
|
});
|
|
32
33
|
return;
|
|
33
34
|
}
|
|
@@ -6,21 +6,21 @@ import {
|
|
|
6
6
|
shouldSkipContentScan,
|
|
7
7
|
} from "./utils.js";
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
/OPENAI_API_KEY\s*=/i,
|
|
11
|
-
/DATABASE_URL\s*=/i,
|
|
12
|
-
/JWT_SECRET\s*=/i,
|
|
13
|
-
/AUTH_SECRET\s*=/i,
|
|
14
|
-
/PRIVATE_KEY\s*=/i,
|
|
15
|
-
/SECRET_KEY\s*=/i,
|
|
16
|
-
/sk-[A-Za-z0-9_-]{20,}/,
|
|
17
|
-
/ghp_[A-Za-z0-9]{36,}/,
|
|
18
|
-
/github_pat_[A-Za-z0-9_]+/,
|
|
19
|
-
/AKIA[0-9A-Z]{16}/,
|
|
20
|
-
/sk_live_[A-Za-z0-9]+/,
|
|
21
|
-
/AIza[0-9A-Za-z_-]{35}/,
|
|
22
|
-
/hooks\.slack\.com\/services\//,
|
|
23
|
-
/password\s*=\s*['"][^'"]{8,}['"]/i,
|
|
9
|
+
const secretRules: { pattern: RegExp; label: string }[] = [
|
|
10
|
+
{ pattern: /OPENAI_API_KEY\s*=/i, label: "OpenAI API key" },
|
|
11
|
+
{ pattern: /DATABASE_URL\s*=/i, label: "database connection string" },
|
|
12
|
+
{ pattern: /JWT_SECRET\s*=/i, label: "JWT secret" },
|
|
13
|
+
{ pattern: /AUTH_SECRET\s*=/i, label: "auth secret" },
|
|
14
|
+
{ pattern: /PRIVATE_KEY\s*=/i, label: "private key" },
|
|
15
|
+
{ pattern: /SECRET_KEY\s*=/i, label: "secret key" },
|
|
16
|
+
{ pattern: /sk-[A-Za-z0-9_-]{20,}/, label: "API key" },
|
|
17
|
+
{ pattern: /ghp_[A-Za-z0-9]{36,}/, label: "GitHub personal access token" },
|
|
18
|
+
{ pattern: /github_pat_[A-Za-z0-9_]+/, label: "GitHub personal access token" },
|
|
19
|
+
{ pattern: /AKIA[0-9A-Z]{16}/, label: "AWS access key" },
|
|
20
|
+
{ pattern: /sk_live_[A-Za-z0-9]+/, label: "Stripe live secret key" },
|
|
21
|
+
{ pattern: /AIza[0-9A-Za-z_-]{35}/, label: "Google API key" },
|
|
22
|
+
{ pattern: /hooks\.slack\.com\/services\//, label: "Slack webhook URL" },
|
|
23
|
+
{ pattern: /password\s*=\s*['"][^'"]{8,}['"]/i, label: "hardcoded password" },
|
|
24
24
|
];
|
|
25
25
|
|
|
26
26
|
export const secretCheck: Check = {
|
|
@@ -38,16 +38,16 @@ export const secretCheck: Check = {
|
|
|
38
38
|
lines.forEach((line, index) => {
|
|
39
39
|
if (isCommentLine(line) || isPlaceholderValue(line)) return;
|
|
40
40
|
|
|
41
|
-
for (const
|
|
42
|
-
if (pattern.test(line)) {
|
|
41
|
+
for (const rule of secretRules) {
|
|
42
|
+
if (rule.pattern.test(line)) {
|
|
43
43
|
findings.push({
|
|
44
44
|
severity: "error",
|
|
45
45
|
checkName: this.name,
|
|
46
46
|
file,
|
|
47
47
|
line: index + 1,
|
|
48
|
-
message:
|
|
48
|
+
message: `Possible ${rule.label} — credentials pushed to GitHub can be scraped instantly.`,
|
|
49
49
|
suggestion:
|
|
50
|
-
"Remove the
|
|
50
|
+
"Remove it from the code, unstage the file, and rotate the credential if it was ever pushed.",
|
|
51
51
|
});
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
@@ -39,8 +39,9 @@ export const sensitiveFilenameCheck: Check = {
|
|
|
39
39
|
severity: "error",
|
|
40
40
|
checkName: this.name,
|
|
41
41
|
file,
|
|
42
|
-
message:
|
|
43
|
-
|
|
42
|
+
message:
|
|
43
|
+
"Credential or key file detected — private keys and auth config should not be in Git.",
|
|
44
|
+
suggestion: `Unstage it: git restore --staged ${file}`,
|
|
44
45
|
});
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { isCodeFile } from "../checks/utils.js";
|
|
4
|
+
import { getStagedFiles } from "../git.js";
|
|
5
|
+
import type { WipFixOptions } from "../types.js";
|
|
6
|
+
|
|
7
|
+
const CONSOLE_LOG_LINE = /^\s*console\.log\([^)]*\);?\s*$/;
|
|
8
|
+
const DEBUGGER_LINE = /^\s*debugger;?\s*$/;
|
|
9
|
+
|
|
10
|
+
function stripDebugLines(
|
|
11
|
+
content: string,
|
|
12
|
+
options: { removeConsoleLog: boolean; removeDebugger: boolean }
|
|
13
|
+
): { updated: string; removed: number } {
|
|
14
|
+
const lines = content.split("\n");
|
|
15
|
+
const kept: string[] = [];
|
|
16
|
+
let removed = 0;
|
|
17
|
+
|
|
18
|
+
for (const line of lines) {
|
|
19
|
+
const isConsoleLog = CONSOLE_LOG_LINE.test(line);
|
|
20
|
+
const isDebugger = DEBUGGER_LINE.test(line);
|
|
21
|
+
|
|
22
|
+
if (
|
|
23
|
+
(options.removeConsoleLog && isConsoleLog) ||
|
|
24
|
+
(options.removeDebugger && isDebugger)
|
|
25
|
+
) {
|
|
26
|
+
removed += 1;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
kept.push(line);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { updated: kept.join("\n"), removed };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function fixDebugCode(
|
|
36
|
+
cwd = process.cwd(),
|
|
37
|
+
options: WipFixOptions = {}
|
|
38
|
+
): string[] {
|
|
39
|
+
const removeConsoleLog = Boolean(options.fixConsoleLog);
|
|
40
|
+
const removeDebugger = true;
|
|
41
|
+
|
|
42
|
+
if (!removeConsoleLog && !removeDebugger) {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let stagedFiles: string[];
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
stagedFiles = getStagedFiles();
|
|
50
|
+
} catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const fixed: string[] = [];
|
|
55
|
+
|
|
56
|
+
for (const file of stagedFiles) {
|
|
57
|
+
if (!isCodeFile(file)) continue;
|
|
58
|
+
|
|
59
|
+
const absolutePath = path.resolve(cwd, file);
|
|
60
|
+
if (!fs.existsSync(absolutePath)) continue;
|
|
61
|
+
|
|
62
|
+
const content = fs.readFileSync(absolutePath, "utf-8");
|
|
63
|
+
const { updated, removed } = stripDebugLines(content, {
|
|
64
|
+
removeConsoleLog,
|
|
65
|
+
removeDebugger,
|
|
66
|
+
});
|
|
67
|
+
if (removed === 0) continue;
|
|
68
|
+
|
|
69
|
+
fs.writeFileSync(absolutePath, updated, "utf-8");
|
|
70
|
+
fixed.push(file);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return fixed;
|
|
74
|
+
}
|