Files
pikasTech-HWLAB/web/hwlab-cloud-web/scripts/dist-contract.mjs
T
2026-05-23 02:27:11 +00:00

133 lines
3.8 KiB
JavaScript

import fs from "node:fs";
import { readFile } from "node:fs/promises";
import path from "node:path";
export const cloudWebDistPath = "web/hwlab-cloud-web/dist";
export const cloudWebDistBuildCommand = "node web/hwlab-cloud-web/scripts/build.mjs";
export const cloudWebDistFreshnessCommand = cloudWebDistBuildCommand;
export const cloudWebDistRuntimeFiles = Object.freeze([
"index.html",
"styles.css",
"app.mjs",
"gate-summary.mjs",
"runtime.mjs",
"workbench-hardware-panel.mjs",
"help.md",
"third_party/marked/marked.esm.js",
"third_party/marked/LICENSE"
]);
export const cloudWebDistAliasFiles = Object.freeze(["gate/index.html", "diagnostics/gate/index.html", "help/index.html"]);
function absolutePath(rootDir, relativePath) {
return path.resolve(rootDir, relativePath);
}
function exists(filePath) {
return fs.existsSync(filePath);
}
async function compareFile({ files, mismatches, kind, relativePath, sourcePath, distPath }) {
const entry = {
kind,
path: relativePath,
sourcePath,
distPath,
status: "match"
};
if (!exists(sourcePath)) {
entry.status = "missing_source";
entry.reason = "source file is missing";
} else if (!exists(distPath)) {
entry.status = "missing_dist";
entry.reason = "dist file is missing";
} else {
const [sourceText, distText] = await Promise.all([
readFile(sourcePath, "utf8"),
readFile(distPath, "utf8")
]);
if (sourceText !== distText) {
entry.status = "mismatch";
entry.reason = "dist file differs from source";
}
}
if (entry.status !== "match") {
mismatches.push(relativePath);
}
files.push(entry);
}
export function buildCloudWebDist(rootDir) {
const distRoot = absolutePath(rootDir, "dist");
fs.rmSync(distRoot, { recursive: true, force: true });
fs.mkdirSync(distRoot, { recursive: true });
for (const relativePath of cloudWebDistRuntimeFiles) {
const distPath = absolutePath(distRoot, relativePath);
fs.mkdirSync(path.dirname(distPath), { recursive: true });
fs.copyFileSync(absolutePath(rootDir, relativePath), distPath);
}
for (const aliasPath of cloudWebDistAliasFiles) {
const distPath = absolutePath(distRoot, aliasPath);
fs.mkdirSync(path.dirname(distPath), { recursive: true });
fs.copyFileSync(absolutePath(rootDir, "index.html"), distPath);
}
return distRoot;
}
export async function inspectCloudWebDistFreshness(rootDir) {
const distRoot = absolutePath(rootDir, "dist");
const files = [];
const mismatches = [];
for (const relativePath of cloudWebDistRuntimeFiles) {
await compareFile({
files,
mismatches,
kind: "runtime",
relativePath,
sourcePath: absolutePath(rootDir, relativePath),
distPath: absolutePath(distRoot, relativePath)
});
}
for (const aliasPath of cloudWebDistAliasFiles) {
await compareFile({
files,
mismatches,
kind: "alias",
relativePath: aliasPath,
sourcePath: absolutePath(rootDir, "index.html"),
distPath: absolutePath(distRoot, aliasPath)
});
}
return {
status: mismatches.length === 0 ? "pass" : "blocked",
distPath: cloudWebDistPath,
buildCommand: cloudWebDistBuildCommand,
freshnessCommand: cloudWebDistFreshnessCommand,
files,
mismatches
};
}
export function cloudWebDistFreshnessMessage(distFreshness) {
const mismatches = distFreshness.mismatches.length > 0 ? distFreshness.mismatches.join(", ") : "unknown";
return [
`Cloud Web dist is stale or missing before image build: ${mismatches}.`,
`Run ${cloudWebDistBuildCommand} before publishing ${cloudWebDistPath}.`
].join(" ");
}
export async function assertCloudWebDistFresh(rootDir) {
const distFreshness = await inspectCloudWebDistFreshness(rootDir);
if (distFreshness.status !== "pass") {
throw new Error(cloudWebDistFreshnessMessage(distFreshness));
}
return distFreshness;
}