refactor: share duplicate script helpers

This commit is contained in:
Peter Steinberger
2026-04-18 21:08:52 +01:00
parent 1687c672a7
commit 1d7d268a63
18 changed files with 347 additions and 682 deletions

View File

@@ -7,7 +7,9 @@ import ts from "typescript";
import { BUNDLED_PLUGIN_PATH_PREFIX } from "./lib/bundled-plugin-paths.mjs";
import {
collectTypeScriptInventory,
createCachedAsync,
diffInventoryEntries,
formatGroupedInventoryHuman,
normalizeRepoPath,
runBaselineInventoryCheck,
resolveRepoSpecifier,
@@ -28,8 +30,6 @@ const baselinePath = path.join(
"fixtures",
"plugin-extension-import-boundary-inventory.json",
);
let cachedInventoryPromise = null;
let cachedExpectedInventoryPromise = null;
const bundledWebSearchProviders = new Set([
"brave",
@@ -158,79 +158,42 @@ function shouldSkipFile(filePath) {
);
}
export async function collectPluginExtensionImportBoundaryInventory() {
if (cachedInventoryPromise) {
return cachedInventoryPromise;
}
export const collectPluginExtensionImportBoundaryInventory = createCachedAsync(async () => {
const files = (await collectTypeScriptFilesFromRoots(scanRoots))
.filter((filePath) => !shouldSkipFile(filePath))
.toSorted((left, right) =>
normalizeRepoPath(repoRoot, left).localeCompare(normalizeRepoPath(repoRoot, right)),
);
return await collectTypeScriptInventory({
ts,
files,
compareEntries,
collectEntries(sourceFile, filePath) {
return [
...scanImportBoundaryViolations(sourceFile, filePath),
...scanWebSearchRegistrySmells(sourceFile, filePath),
];
},
});
});
cachedInventoryPromise = (async () => {
const files = (await collectTypeScriptFilesFromRoots(scanRoots))
.filter((filePath) => !shouldSkipFile(filePath))
.toSorted((left, right) =>
normalizeRepoPath(repoRoot, left).localeCompare(normalizeRepoPath(repoRoot, right)),
);
return await collectTypeScriptInventory({
ts,
files,
compareEntries,
collectEntries(sourceFile, filePath) {
return [
...scanImportBoundaryViolations(sourceFile, filePath),
...scanWebSearchRegistrySmells(sourceFile, filePath),
];
},
});
})();
try {
return await cachedInventoryPromise;
} catch (error) {
cachedInventoryPromise = null;
throw error;
}
}
export async function readExpectedInventory() {
if (cachedExpectedInventoryPromise) {
return cachedExpectedInventoryPromise;
}
cachedExpectedInventoryPromise = fs
.readFile(baselinePath, "utf8")
.then((contents) => JSON.parse(contents));
try {
return await cachedExpectedInventoryPromise;
} catch (error) {
cachedExpectedInventoryPromise = null;
throw error;
}
}
export const readExpectedInventory = createCachedAsync(async () =>
JSON.parse(await fs.readFile(baselinePath, "utf8")),
);
export function diffInventory(expected, actual) {
return diffInventoryEntries(expected, actual, compareEntries);
}
function formatInventoryHuman(inventory) {
if (inventory.length === 0) {
return "Rule: src/plugins/** must not import bundled plugin files\nNo plugin import boundary violations found.";
}
const lines = [
"Rule: src/plugins/** must not import bundled plugin files",
"Plugin extension import boundary inventory:",
];
let activeFile = "";
for (const entry of inventory) {
if (entry.file !== activeFile) {
activeFile = entry.file;
lines.push(activeFile);
}
lines.push(` - line ${entry.line} [${entry.kind}] ${entry.reason}`);
lines.push(` specifier: ${entry.specifier}`);
lines.push(` resolved: ${entry.resolvedPath}`);
}
return lines.join("\n");
}
const formatInventoryHuman = (inventory) =>
formatGroupedInventoryHuman(
{
rule: "Rule: src/plugins/** must not import bundled plugin files",
cleanMessage: "No plugin import boundary violations found.",
inventoryTitle: "Plugin extension import boundary inventory:",
},
inventory,
);
function formatEntry(entry) {
return `${entry.file}:${entry.line} [${entry.kind}] ${entry.reason} (${entry.specifier} -> ${entry.resolvedPath})`;