75 lines
2.4 KiB
JavaScript
75 lines
2.4 KiB
JavaScript
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
|
|
import {
|
|
scanOptionalRecipeSources,
|
|
scanProductionBundle,
|
|
validateRecipeCatalog,
|
|
} from "./lib/optional-recipes.mjs";
|
|
|
|
/** @param {string} name @param {string} fallback */
|
|
const argument = (name, fallback) => {
|
|
const index = process.argv.indexOf(name);
|
|
return index === -1 ? fallback : process.argv[index + 1];
|
|
};
|
|
|
|
const catalogPath = argument(
|
|
"--catalog",
|
|
"config/recipes/frontend-capability-recipes.json",
|
|
);
|
|
const sourceRoot = argument("--source-root", "src");
|
|
const distRoot = argument("--dist-root", "dist");
|
|
const artifactPath = argument(
|
|
"--artifact",
|
|
"artifacts/quality/optional-recipes.json",
|
|
);
|
|
const requireDist = process.argv.includes("--require-dist");
|
|
|
|
const catalog = JSON.parse(await readFile(catalogPath, "utf8"));
|
|
const packageDocument = JSON.parse(await readFile("package.json", "utf8"));
|
|
const catalogViolations = validateRecipeCatalog(catalog, packageDocument);
|
|
const sourceViolations = await scanOptionalRecipeSources(sourceRoot);
|
|
const bundlePresent = await stat(`${distRoot}/.vite/manifest.json`)
|
|
.then(() => true)
|
|
.catch(() => false);
|
|
const bundleViolations = await scanProductionBundle(distRoot);
|
|
const violations = [
|
|
...catalogViolations.map((ruleId) => ({ ruleId, path: catalogPath })),
|
|
...sourceViolations,
|
|
...bundleViolations.map((path) => ({
|
|
ruleId: "UNSELECTED_RECIPE_IN_PRODUCTION_BUNDLE",
|
|
path,
|
|
})),
|
|
...(requireDist && !bundlePresent
|
|
? [{ ruleId: "PRODUCTION_BUNDLE_MISSING", path: distRoot }]
|
|
: []),
|
|
];
|
|
const report = {
|
|
schemaVersion: 1,
|
|
decisionId: "VD-10",
|
|
selectedCapabilities: [],
|
|
recipeCount: Array.isArray(catalog.recipes) ? catalog.recipes.length : 0,
|
|
productionRuntimeDependencies:
|
|
catalog.productionRuntimeDependencies ?? null,
|
|
bundleStatus: bundlePresent
|
|
? bundleViolations.length === 0
|
|
? "PASS"
|
|
: "FAIL"
|
|
: "NOT_BUILT",
|
|
violations,
|
|
passed: violations.length === 0,
|
|
};
|
|
await mkdir("artifacts/quality", { recursive: true });
|
|
await writeFile(artifactPath, `${JSON.stringify(report, null, 2)}\n`);
|
|
|
|
if (violations.length > 0) {
|
|
process.stderr.write(
|
|
`Optional recipe contract failed:\n${violations
|
|
.map((violation) => `${violation.ruleId}: ${violation.path}`)
|
|
.join("\n")}\n`,
|
|
);
|
|
process.exit(1);
|
|
}
|
|
process.stdout.write(
|
|
`Optional recipes: PASS (${report.recipeCount} recipe-only capabilities, bundle=${report.bundleStatus})\n`,
|
|
);
|