import { readFileSync } from "node:fs"; import { CliError } from "./errors.js"; function isRecord(value: unknown): value is Record { return Boolean(value) && typeof value === "object" && !Array.isArray(value); } export function readJsonFile(path: string, label: string): unknown { try { return JSON.parse(readFileSync(path, "utf8")); } catch (error) { if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") { throw new CliError("CLI 参数错误", "INPUT_NOT_FOUND", `${label} file not found: ${path}`, 2); } if (error instanceof SyntaxError) throw new CliError("CLI 参数错误", "INPUT_INVALID_JSON", `${label} file must be valid JSON: ${path}`, 2); throw error; } } export function parseBurstFile(path: string): [string[], number[]] { let raw = readJsonFile(path, "burst"); if (isRecord(raw) && "bursts" in raw) raw = raw.bursts; if (isRecord(raw) && "burst_ID" in raw && "burst_size" in raw && Array.isArray(raw.burst_ID) && Array.isArray(raw.burst_size)) { const ids = raw.burst_ID.map(String); const sizes = raw.burst_size.map(Number); if (ids.length !== sizes.length) throw new CliError("CLI 参数错误", "BURST_FILE_INVALID", "burst file burst_ID and burst_size must have the same length", 2); return [ids, sizes]; } if (Array.isArray(raw)) { return [ raw.map((item) => { if (!isRecord(item) || !("id" in item) || !("size" in item)) throw new CliError("CLI 参数错误", "BURST_FILE_INVALID", "burst file items must contain id and size", 2); return String(item.id); }), raw.map((item) => Number((item as Record).size)), ]; } throw new CliError("CLI 参数错误", "BURST_FILE_INVALID", "burst file must be a JSON array or object with burst_ID/burst_size", 2); } export function parseValveSettingFile(path: string): [string[], number[]] { const raw = readJsonFile(path, "valve-setting"); if (isRecord(raw) && "valves" in raw && "valves_k" in raw && Array.isArray(raw.valves) && Array.isArray(raw.valves_k)) { const valves = raw.valves.map(String); const openings = raw.valves_k.map(Number); if (valves.length !== openings.length) throw new CliError("CLI 参数错误", "VALVE_SETTING_INVALID", "valves and valves_k must have the same length", 2); return [valves, openings]; } if (Array.isArray(raw)) { return [ raw.map((item) => { if (!isRecord(item) || !("valve" in item) || !("opening" in item)) throw new CliError("CLI 参数错误", "VALVE_SETTING_INVALID", "valve-setting items must contain valve and opening", 2); return String(item.valve); }), raw.map((item) => Number((item as Record).opening)), ]; } throw new CliError("CLI 参数错误", "VALVE_SETTING_INVALID", "valve-setting file must be a JSON array or object with valves/valves_k", 2); } export function assignDatasetKeys(target: Record, path: string, keys: string[], label: string): void { const payload = readJsonFile(path, label); if (isRecord(payload)) { for (const key of keys) { if (key in payload) target[key] = payload[key]; } } }