refactor: split renderer ipc and unraid domains

This commit is contained in:
NuklearRabbit
2026-07-29 18:11:07 +02:00
parent 5d3731a853
commit 7b05c953b6
36 changed files with 9316 additions and 8330 deletions
+53
View File
@@ -0,0 +1,53 @@
import { readdir, readFile, writeFile, mkdir } from "node:fs/promises";
import path from "node:path";
const root = path.resolve(import.meta.dirname, "..");
const sourceRoots = ["main.cjs", "preload.cjs", "src/main", "src/renderer", "src/shared"];
const extensions = new Set([".js", ".cjs", ".mjs"]);
async function filesBelow(entry) {
const absolute = path.join(root, entry);
const stat = await import("node:fs/promises").then(({ stat }) => stat(absolute));
if (stat.isFile()) return [entry];
const result = [];
for (const child of await readdir(absolute, { withFileTypes: true })) {
const relative = path.join(entry, child.name);
if (child.isDirectory()) result.push(...await filesBelow(relative));
else if (extensions.has(path.extname(child.name))) result.push(relative);
}
return result;
}
function analyze(relative, source) {
const lines = source.split(/\r?\n/).length;
const branches = (source.match(/\b(?:if|else if|for|while|case|catch)\b|\?\?/g) || []).length;
const functions = (source.match(/\b(?:async\s+)?function\b|=>|\b(?:async\s+)?[A-Za-z_$][\w$]*\s*\([^)]*\)\s*\{/g) || []).length;
const ipcHandlers = (source.match(/\bregister\(\s*["']/g) || []).length;
const responsibilities = [
["inventory", /inventory|workload/i], ["deployment", /deploy|rollback|activation/i],
["git", /\bgit|repository/i], ["ipc", /ipc|register\(/i], ["renderer", /render|modal|document\./i],
["security", /key|credential|signature|checksum/i], ["updates", /update|release|artifact/i],
].filter(([, pattern]) => pattern.test(source)).map(([name]) => name);
return { file: relative.replaceAll("\\", "/"), lines, branches, functions, ipcHandlers, responsibilities, hotspotScore: branches + Math.max(0, responsibilities.length - 2) * 10 };
}
const files = (await Promise.all(sourceRoots.map(filesBelow))).flat();
const results = [];
for (const file of files) results.push(analyze(file, await readFile(path.join(root, file), "utf8")));
results.sort((a, b) => b.hotspotScore - a.hotspotScore || b.lines - a.lines);
const report = {
generatedAt: new Date().toISOString(),
thresholds: { preferredMaximumLines: 750, justificationRequiredLines: 1000 },
over750: results.filter((item) => item.lines > 750),
over1000: results.filter((item) => item.lines > 1000),
cyclomaticHotspots: results.filter((item) => item.branches >= 75).slice(0, 20),
mixedResponsibilityModules: results.filter((item) => item.responsibilities.length >= 4),
ipcHotspots: results.filter((item) => item.ipcHandlers >= 10),
};
const reportDir = path.join(root, "reports");
await mkdir(reportDir, { recursive: true });
await writeFile(path.join(reportDir, "architecture-audit.json"), `${JSON.stringify(report, null, 2)}\n`);
const table = (items) => items.length ? items.map((item) => `| \`${item.file}\` | ${item.lines} | ${item.branches} | ${item.functions} | ${item.ipcHandlers} | ${item.responsibilities.join(", ")} |`).join("\n") : "No findings.";
const markdown = `# ForgeFlow architecture audit\n\nGenerated ${report.generatedAt}. Complexity is a deterministic decision-point count used for hotspot ranking, not a claim of exact McCabe complexity.\n\n## Files above 750 lines\n\n| File | Lines | Decisions | Functions | IPC handlers | Responsibilities |\n|---|---:|---:|---:|---:|---|\n${table(report.over750)}\n\n## Files above 1,000 lines\n\n| File | Lines | Decisions | Functions | IPC handlers | Responsibilities |\n|---|---:|---:|---:|---:|---|\n${table(report.over1000)}\n\n## Cyclomatic hotspots\n\n| File | Lines | Decisions | Functions | IPC handlers | Responsibilities |\n|---|---:|---:|---:|---:|---|\n${table(report.cyclomaticHotspots)}\n\n## Interpretation\n\nFiles above 750 lines require decomposition. Files above 1,000 lines are release blockers unless a concrete technical exception is documented. Mixed responsibility and IPC hotspot lists are available in the JSON report.\n`;
await writeFile(path.join(reportDir, "architecture-audit.md"), markdown);
console.log(`Audited ${results.length} source files; ${report.over750.length} exceed 750 lines and ${report.over1000.length} exceed 1,000 lines.`);
+11 -7
View File
@@ -313,13 +313,17 @@ if (
)
throw new Error("PowerShell update helper must start directly with param(.");
const renderer = await readFile(path.join(root, "src/renderer/app.js"), "utf8");
const renderer = (await Promise.all(["app.js", "views.js", "dialogs.js", "operations.js", "actions/shell.js", "actions/inventory.js", "actions/deployment-profile.js", "actions/deployment-operation.js", "actions/setup-and-settings.js", "actions/recovery.js", "actions/command.js", "events.js"].map((file) =>
readFile(path.join(root, "src/renderer", file), "utf8"),
))).join("\n");
const styles = await readFile(
path.join(root, "src/renderer/styles.css"),
"utf8",
);
const preload = await readFile(path.join(root, "preload.cjs"), "utf8");
const ipc = await readFile(path.join(root, "src/main/ipc.cjs"), "utf8");
const ipc = (await Promise.all(["ipc.cjs", "ipc/repository-handlers.cjs", "ipc/deployment-handlers.cjs", "ipc/operations-handlers.cjs"].map((file) =>
readFile(path.join(root, "src/main", file), "utf8"),
))).join("\n");
for (const phrase of [
'data-action="commit-push"',
"checkForUpdates",
@@ -434,7 +438,10 @@ const configSource = await readFile(path.join(root, "src/main/config-store.cjs")
for (const mode of ["server-git", "push-bundle", "monitor-only"]) {
if (!configSource.includes(mode)) throw new Error(`Deployment configuration is missing mode: ${mode}`);
}
const unraidDirectSource = await readFile(path.join(root, "src/main/unraid-deployment-service.cjs"), "utf8");
const unraidDirectSource = (await Promise.all([
"unraid-deployment-service.cjs", "unraid-access-methods.cjs", "unraid-preflight-methods.cjs",
"unraid-runtime-methods.cjs", "unraid-deployment-methods.cjs", "unraid-inventory-methods.cjs", "unraid-state-methods.cjs",
].map((file) => readFile(path.join(root, "src/main", file), "utf8")))).join("\n");
for (const requiredPhrase of [
"executePushBundle",
"executeServerGitBundle",
@@ -462,10 +469,7 @@ const gitSource = await readFile(
path.join(root, "src/main/git-service.cjs"),
"utf8",
);
const unraidSource = await readFile(
path.join(root, "src/main/unraid-deployment-service.cjs"),
"utf8",
);
const unraidSource = unraidDirectSource;
const publisher = await readFile(
path.join(root, "Publish-ForgeFlow-Release.ps1"),
"utf8",