Files
paperclip/scripts/check-forbidden-tokens.mjs
Dotta 4c6fe04700 feat: add npm build process, version bump, and forbidden token enforcement
- Add esbuild config to bundle CLI with all workspace code for npm publishing
- Add build-npm.sh script that runs forbidden token check, type-check,
  esbuild bundle, and generates publishable package.json
- Add generate-npm-package-json.mjs to resolve workspace:* refs to actual
  npm dependencies for publishing
- Add version-bump.sh for patch/minor/major/explicit version bumping
- Add check-forbidden-tokens.mjs that scans codebase for forbidden tokens
  (mirrors git hook logic, safe if token list is missing)
- Add esbuild as dev dependency
- Add build:npm, version:bump, check:tokens scripts to root package.json
- Update .gitignore for build artifacts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:25:10 -06:00

68 lines
2.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* check-forbidden-tokens.mjs
*
* Scans the codebase for forbidden tokens before publishing to npm.
* Mirrors the git pre-commit hook logic, but runs against the full
* working tree (not just staged changes).
*
* Token list: .git/hooks/forbidden-tokens.txt (one per line, # comments ok).
* If the file is missing, the check passes silently — other developers
* on the project won't have this list, and that's fine.
*/
import { execSync } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
const repoRoot = execSync("git rev-parse --show-toplevel", { encoding: "utf8" }).trim();
const gitDir = execSync("git rev-parse --git-dir", { encoding: "utf8", cwd: repoRoot }).trim();
const tokensFile = resolve(repoRoot, gitDir, "hooks/forbidden-tokens.txt");
if (!existsSync(tokensFile)) {
console.log(" Forbidden tokens list not found — skipping check.");
process.exit(0);
}
const tokens = readFileSync(tokensFile, "utf8")
.split("\n")
.map((l) => l.trim())
.filter((l) => l && !l.startsWith("#"));
if (tokens.length === 0) {
console.log(" Forbidden tokens list is empty — skipping check.");
process.exit(0);
}
// Use git grep to search tracked files only (avoids node_modules, dist, etc.)
let found = false;
for (const token of tokens) {
try {
const result = execSync(
`git grep -in --no-color -- ${JSON.stringify(token)} -- ':!pnpm-lock.yaml' ':!.git'`,
{ encoding: "utf8", cwd: repoRoot, stdio: ["pipe", "pipe", "pipe"] },
);
if (result.trim()) {
if (!found) {
console.error("ERROR: Forbidden tokens found in tracked files:\n");
}
found = true;
// Print matches but DO NOT print which token was matched (avoids leaking the list)
const lines = result.trim().split("\n");
for (const line of lines) {
console.error(` ${line}`);
}
}
} catch {
// git grep returns exit code 1 when no matches — that's fine
}
}
if (found) {
console.error("\nBuild blocked. Remove the forbidden token(s) before publishing.");
process.exit(1);
} else {
console.log(" ✓ No forbidden tokens found.");
}