/* * SPEC: PJ2026-010101 HWPOD 标准;PJ2026-010102 HWPOD 工具。 * 责任: 提供 HWPOD spec document 的共享标准化与校验。 */ export function normalizeHwpodSpec(document: any, specPath: string) { const root = objectValue(document); if (root.kind !== "Hwpod") throw codedError("invalid_hwpod_spec_kind", "hwpod-spec kind must be Hwpod", { specPath, kind: root.kind }); const spec = objectValue(root.spec); const metadata = objectValue(root.metadata); for (const key of ["targetDevice", "workspace", "debugProbe", "ioProbe"]) { if (!isPlainObject(spec[key])) throw codedError("invalid_hwpod_spec_element", `hwpod-spec missing ${key}`, { specPath, element: key }); } const workspacePath = requiredText(spec.workspace.path, "spec.workspace.path"); const nodeBinding = objectValue(spec.nodeBinding); const nodeId = requiredText(nodeBinding.nodeId, "spec.nodeBinding.nodeId"); const name = requiredText(metadata.name ?? metadata.uid, "metadata.name"); return { apiVersion: text(root.apiVersion) || "hwlab.pikastech.com/v1alpha1", kind: "Hwpod", metadata: { ...metadata, name }, spec: { ...spec, nodeBinding: { ...nodeBinding, nodeId }, workspace: { ...spec.workspace, path: workspacePath }, targetDevice: spec.targetDevice, debugProbe: spec.debugProbe, ioProbe: spec.ioProbe, }, }; } function objectValue(value: unknown) { return isPlainObject(value) ? value as Record : {}; } function isPlainObject(value: unknown) { return Boolean(value && typeof value === "object" && !Array.isArray(value)); } function text(value: unknown) { return typeof value === "string" && value.trim() ? value.trim() : ""; } function requiredText(value: unknown, name: string) { const normalized = text(value); if (!normalized) throw codedError("required_option_missing", `${name} is required`, { name }); return normalized; } function codedError(code: string, message: string, details: Record = {}) { return Object.assign(new Error(message), { code, details }); }