detect-console-log
Version:
Warn if console.log appears in staged changes (Husky pre-commit).
143 lines (139 loc) • 3.84 kB
JavaScript
;
// src/git-utils.ts
var import_child_process = require("child_process");
function run(cmd) {
return (0, import_child_process.execSync)(cmd, {
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"]
}).trim();
}
function tryRun(cmd) {
try {
return run(cmd);
} catch {
return "";
}
}
function hasHead() {
try {
(0, import_child_process.execSync)("git rev-parse --verify HEAD", { stdio: "ignore" });
return true;
} catch {
return false;
}
}
function getEmptyTreeOid() {
return run("git hash-object -t tree /dev/null");
}
function getCachedDiff() {
const base = hasHead() ? "HEAD" : getEmptyTreeOid();
return tryRun(`git diff --cached --unified=0 --no-color --diff-filter=ACMR ${base}`);
}
var parseFileName = (line) => {
const path = line.slice(4).trim();
return path === "/dev/null" ? null : path.replace(/^([ab]\/)*/, "");
};
var parseHunkLine = (line) => {
const hunkRe = /@@\s*-\d+(?:,\d+)?\s*\+(\d+)(?:,(\d+))?\s*@@/;
const match = hunkRe.exec(line);
return match ? Number(match[1]) || 0 : 0;
};
var isAddedLine = (line) => {
return line.startsWith("+") && !line.startsWith("+++");
};
var hasConsoleLog = (text) => {
return /\bconsole\.log\b/.test(text);
};
var parseDiffForLogs = (diff) => {
const results = [];
let file = null;
let nextLine = 0;
for (const raw of diff.split("\n")) {
if (raw.startsWith("diff --git ")) {
file = null;
continue;
}
if (raw.startsWith("+++ ")) {
file = parseFileName(raw);
continue;
}
if (!file) continue;
if (raw.startsWith("@@")) {
nextLine = parseHunkLine(raw);
continue;
}
if (isAddedLine(raw)) {
const added = raw.slice(1);
if (hasConsoleLog(added)) {
results.push({ file, line: nextLine, text: added });
}
nextLine += 1;
}
}
return results;
};
// src/print-utils.ts
var colors = {
reset: "\x1B[0m",
bright: "\x1B[1m",
red: "\x1B[31m",
yellow: "\x1B[33m",
blue: "\x1B[34m",
magenta: "\x1B[35m",
cyan: "\x1B[36m",
white: "\x1B[37m",
gray: "\x1B[90m",
bgRed: "\x1B[41m",
bgYellow: "\x1B[43m"
};
var colorize = (text, color) => {
return `${colors[color]}${text}${colors.reset}`;
};
var printResults = (matches, failOnFound) => {
if (!matches.length) return;
console.log();
if (failOnFound) {
console.log(colorize("\u274C Console Log Checker Error \u274C", "red"));
console.log(colorize("\u2501".repeat(50), "red"));
} else {
console.log(colorize("\u26A0\uFE0F Console Log Checker Warning \u26A0\uFE0F", "yellow"));
console.log(colorize("\u2501".repeat(40), "yellow"));
}
console.log(
colorize(
`Found ${colorize(matches.length.toString(), "bright")} console.log${matches.length > 1 ? "s" : ""} in staged changes:`,
"white"
)
);
console.log();
const grouped = /* @__PURE__ */ new Map();
for (const m of matches) {
if (!grouped.has(m.file)) grouped.set(m.file, []);
grouped.get(m.file).push(m);
}
for (const [f, rows] of grouped) {
console.log(colorize(`\u{1F4C1} ${f}`, "cyan"));
for (const { line, text } of rows) {
const snippet = text.length > 200 ? text.slice(0, 197) + "\u2026" : text;
console.log(colorize(` \u21B3 L${line}:`, "gray") + " " + colorize(snippet.trim(), "magenta"));
}
console.log();
}
console.log();
};
// src/detect-console-log.ts
var main = async () => {
const args = process.argv.slice(2);
const failOnFound = args.includes("--fail-on-found");
const diff = getCachedDiff();
if (!diff) process.exit(0);
const matches = parseDiffForLogs(diff);
if (!matches.length) process.exit(0);
printResults(matches, failOnFound);
if (failOnFound) process.exit(1);
};
main().catch((err) => {
console.error(err);
process.exit(1);
});