141 lines · 3.9 KB · JavaScript
RawDownload
#!/usr/bin/env nodeimport { readFileSync, readdirSync } from "node:fs";import { join, relative, resolve } from "node:path"; const root = resolve(import.meta.dirname, "..");const contractNames = [  "Backend",  "ServeRuntimeKind",  "ServeRuntime",  "Serve",  "ServePayload",  "RecipeBase",  "RecipePayload",  "DownloadStatus",  "DownloadFileStatus",  "DownloadFileInfo",  "ModelDownload",  "StorageInfo",  "ModelInfo",  "ServiceInfo",  "SystemConfig",  "EnvironmentInfo",  "Environment",  "EnvironmentEngineId",  "RuntimeBackendInfo",  "EngineBackend",  "RuntimeKind",  "RuntimeTarget",  "EngineJob",  "RuntimePlatformKind",  "RuntimeRocmSmiTool",  "RuntimeGpuMonitoringTool",  "RuntimeCudaInfo",  "RuntimeRocmInfo",  "RuntimeTorchBuildInfo",  "RuntimePlatformInfo",  "RuntimeGpuMonitoringInfo",  "RuntimeGpuInfoSummary",  "CompatibilitySeverity",  "CompatibilityCheck",  "SystemRuntimeInfo",  "CompatibilityReport",  "ConfigData",  "RuntimeUpgradeResult",  "ControllerEventType",  "ControllerStreamEventType",  "ControllerEventDomain",  "ControllerBrowserEventChannel",  "GPU",  "Metrics",  "VRAMCalculation",  "PeakMetrics",  "ProcessInfo",  "LogSession",  "StudioSettings",  "StudioDiagnostics",  "ControllerUsageStats",  "UsageStats",  "RigHardwareType",  "RigNodeRole",  "RigNodeSource",  "RigAccelerator",  "RigNode",  "Rig",  "RigsPayload",];const allowedFiles = new Set([  "shared/contracts/recipes.ts",  "shared/contracts/system.ts",  "shared/contracts/controller-events.ts",  "shared/contracts/observability.ts",  "shared/contracts/usage.ts",  "shared/contracts/environments.ts",  "shared/contracts/rigs.ts",  "controller/src/modules/shared/recipe-types.ts",  "controller/src/modules/shared/system-types.ts",  "frontend/src/lib/types.ts",  "frontend/src/lib/controller-events-contract.ts",]);const scanRoots = ["shared", "controller/src", "frontend/src"];const findings = [];const exportedDeclarations = new Map(); function walk(dir) {  for (const entry of readdirSync(dir, { withFileTypes: true })) {    if (entry.name.startsWith(".") || entry.name === "node_modules") continue;    const full = join(dir, entry.name);    if (entry.isDirectory()) {      walk(full);      continue;    }    if (entry.isFile() && /\.(ts|tsx)$/.test(entry.name)) inspect(full);  }} function inspect(filePath) {  const rel = relative(root, filePath);  const source = readFileSync(filePath, "utf8");  collectExportedDeclarations(rel, source);  for (const name of contractNames) {    const declaration = new RegExp(`export\\s+(interface|type)\\s+${name}\\b`);    if (declaration.test(source) && !allowedFiles.has(rel)) {      findings.push(`${rel}: ${name}`);    }  }} function collectExportedDeclarations(rel, source) {  const declaration = /\bexport\s+(?:declare\s+)?(?:type|interface)\s+([A-Za-z0-9_]+)/g;  for (const match of source.matchAll(declaration)) {    const name = match[1];    if (!exportedDeclarations.has(name)) exportedDeclarations.set(name, []);    exportedDeclarations.get(name).push(rel);  }} for (const scanRoot of scanRoots) {  walk(join(root, scanRoot));} if (findings.length > 0) {  console.error("Shared contract check failed. Move these declarations to shared/contracts:");  for (const finding of findings) console.error(`- ${finding}`);  process.exit(1);} const duplicateDeclarations = [...exportedDeclarations.entries()]  .filter(([, files]) => files.length > 1)  .sort(([left], [right]) => left.localeCompare(right)); if (duplicateDeclarations.length > 0) {  console.error("Duplicate exported type/interface declarations found:");  for (const [name, files] of duplicateDeclarations) {    console.error(`- ${name}`);    for (const file of files) console.error(`  ${file}`);  }  console.error("Export one declaration and re-export aliases from compatibility barrels instead.");  process.exit(1);} console.log("Shared contract check passed");