refactor(scripts): share guard runners and paged select UI

This commit is contained in:
Peter Steinberger
2026-03-02 14:36:00 +00:00
parent e41f9998f7
commit dbc78243f4
10 changed files with 234 additions and 294 deletions

View File

@@ -0,0 +1,45 @@
import { promises as fs } from "node:fs";
import path from "node:path";
import {
collectTypeScriptFilesFromRoots,
resolveRepoRoot,
resolveSourceRoots,
} from "./ts-guard-utils.mjs";
export async function runCallsiteGuard(params) {
const repoRoot = resolveRepoRoot(params.importMetaUrl);
const sourceRoots = resolveSourceRoots(repoRoot, params.sourceRoots);
const files = await collectTypeScriptFilesFromRoots(sourceRoots, {
extraTestSuffixes: params.extraTestSuffixes,
});
const violations = [];
for (const filePath of files) {
const relPath = path.relative(repoRoot, filePath).replaceAll(path.sep, "/");
if (params.skipRelativePath?.(relPath)) {
continue;
}
const content = await fs.readFile(filePath, "utf8");
for (const line of params.findCallLines(content, filePath)) {
const callsite = `${relPath}:${line}`;
if (params.allowCallsite?.(callsite)) {
continue;
}
violations.push(callsite);
}
}
if (violations.length === 0) {
return;
}
console.error(params.header);
const output = params.sortViolations === false ? violations : violations.toSorted();
for (const violation of output) {
console.error(`- ${violation}`);
}
if (params.footer) {
console.error(params.footer);
}
process.exit(1);
}

View File

@@ -0,0 +1,13 @@
import path from "node:path";
import { resolveRepoRoot, resolveSourceRoots } from "./ts-guard-utils.mjs";
export function createPairingGuardContext(importMetaUrl) {
const repoRoot = resolveRepoRoot(importMetaUrl);
const sourceRoots = resolveSourceRoots(repoRoot, ["src", "extensions"]);
return {
repoRoot,
sourceRoots,
resolveFromRepo: (relativePath) =>
path.join(repoRoot, ...relativePath.split("/").filter(Boolean)),
};
}

View File

@@ -9,6 +9,10 @@ export function resolveRepoRoot(importMetaUrl) {
return path.resolve(path.dirname(fileURLToPath(importMetaUrl)), "..", "..");
}
export function resolveSourceRoots(repoRoot, relativeRoots) {
return relativeRoots.map((root) => path.join(repoRoot, ...root.split("/").filter(Boolean)));
}
export function isTestLikeTypeScriptFile(filePath, options = {}) {
const extraTestSuffixes = options.extraTestSuffixes ?? [];
return [...baseTestSuffixes, ...extraTestSuffixes].some((suffix) => filePath.endsWith(suffix));
@@ -68,18 +72,24 @@ export async function collectTypeScriptFiles(targetPath, options = {}) {
return out;
}
export async function collectFileViolations(params) {
const files = (
export async function collectTypeScriptFilesFromRoots(sourceRoots, options = {}) {
return (
await Promise.all(
params.sourceRoots.map(
sourceRoots.map(
async (root) =>
await collectTypeScriptFiles(root, {
ignoreMissing: true,
extraTestSuffixes: params.extraTestSuffixes,
...options,
}),
),
)
).flat();
}
export async function collectFileViolations(params) {
const files = await collectTypeScriptFilesFromRoots(params.sourceRoots, {
extraTestSuffixes: params.extraTestSuffixes,
});
const violations = [];
for (const filePath of files) {