Files
TJWaterAgent/cli/src/core/files.ts
T
jiang 93d70da8be
Agent CI/CD / deploy-fallback-log (push) Has been cancelled
Agent CI/CD / docker-image (push) Has been cancelled
refactor(cli): split tjwater cli modules
2026-06-07 19:43:44 +08:00

70 lines
3.1 KiB
TypeScript

import { readFileSync } from "node:fs";
import { CliError } from "./errors.js";
function isRecord(value: unknown): value is Record<string, unknown> {
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<string, unknown>).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<string, unknown>).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<string, unknown>, 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];
}
}
}