UNPKG

detect-console-log

Version:

Warn if console.log appears in staged changes (Husky pre-commit).

143 lines (139 loc) 3.84 kB
#!/usr/bin/env node "use strict"; // 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); });