6b417cc620
Co-authored-by: Codex Agent <codex@hwlab.local>
73 lines
2.5 KiB
JavaScript
73 lines
2.5 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
export const defaultPlaywrightLaunchScanRoots = Object.freeze(["scripts", "tools", "web"]);
|
|
export const defaultPlaywrightLaunchAllowlist = Object.freeze([
|
|
"scripts/src/browser-launcher.mjs"
|
|
]);
|
|
|
|
const sourceExtensions = new Set([".cjs", ".cts", ".js", ".jsx", ".mjs", ".mts", ".ts", ".tsx"]);
|
|
const skippedDirectories = new Set([".git", ".state", ".worktree", "dist", "node_modules"]);
|
|
const directChromiumLaunchPattern = new RegExp("\\bchromium\\s*\\.\\s*launch\\s*\\(", "u");
|
|
|
|
export function findDirectChromiumLaunches(options = {}) {
|
|
const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
|
|
const roots = options.roots ?? defaultPlaywrightLaunchScanRoots;
|
|
const allowlist = new Set(options.allowlist ?? defaultPlaywrightLaunchAllowlist);
|
|
const scannedFiles = [];
|
|
const allowed = [];
|
|
const violations = [];
|
|
|
|
for (const root of roots) {
|
|
const absoluteRoot = path.resolve(repoRoot, root);
|
|
if (!fs.existsSync(absoluteRoot)) continue;
|
|
for (const file of collectSourceFiles(absoluteRoot)) {
|
|
const relativePath = normalizeRelative(repoRoot, file);
|
|
scannedFiles.push(relativePath);
|
|
const matches = findMatches(file, relativePath);
|
|
if (matches.length === 0) continue;
|
|
if (allowlist.has(relativePath)) allowed.push(...matches);
|
|
else violations.push(...matches);
|
|
}
|
|
}
|
|
|
|
return {
|
|
status: violations.length === 0 ? "pass" : "fail",
|
|
repoRoot,
|
|
roots,
|
|
allowlist: [...allowlist].sort(),
|
|
scannedFileCount: scannedFiles.length,
|
|
allowed,
|
|
violations
|
|
};
|
|
}
|
|
|
|
function collectSourceFiles(directory) {
|
|
const out = [];
|
|
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
if (entry.isDirectory()) {
|
|
if (!skippedDirectories.has(entry.name)) out.push(...collectSourceFiles(path.join(directory, entry.name)));
|
|
continue;
|
|
}
|
|
if (!entry.isFile()) continue;
|
|
const full = path.join(directory, entry.name);
|
|
if (sourceExtensions.has(path.extname(entry.name))) out.push(full);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
function findMatches(file, relativePath) {
|
|
const lines = fs.readFileSync(file, "utf8").split(/\r?\n/u);
|
|
const matches = [];
|
|
lines.forEach((line, index) => {
|
|
if (directChromiumLaunchPattern.test(line)) {
|
|
matches.push({ file: relativePath, line: index + 1, text: line.trim().slice(0, 200) });
|
|
}
|
|
});
|
|
return matches;
|
|
}
|
|
|
|
function normalizeRelative(root, file) {
|
|
return path.relative(root, file).split(path.sep).join("/");
|
|
}
|