import path from "path"; import type { WorkflowMode } from "./simulation"; import { validateExecutionId } from "./executionId"; export const WORKFLOW_RESULT_NAMES = ["execution", "view", "verification"] as const; export type WorkflowResultName = typeof WORKFLOW_RESULT_NAMES[number]; interface WorkflowResultPathInput { target: string; executionId: string; mode: WorkflowMode; name: WorkflowResultName; } interface WorkflowResultDirectoryInput { target: string; executionId: string; mode: WorkflowMode; } const SAFE_SEGMENT = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9_-])?$/; const confinedSegment = (value: string, label: string): string => { if (!SAFE_SEGMENT.test(value)) { throw new Error(`${label} is not safe for a workflow result path`); } return value; }; const modeSegment = (mode: WorkflowMode): string => { return mode === "simulate" ? "simulation" : mode; }; export const workflowResultRelativeDirectory = ( input: WorkflowResultDirectoryInput, ): string => { return path.posix.join( "results", confinedSegment(input.target, "target"), validateExecutionId(input.executionId), modeSegment(input.mode), ); }; export const workflowResultRelativePath = (input: WorkflowResultPathInput): string => { const name = confinedSegment(input.name, "result name"); return path.posix.join(workflowResultRelativeDirectory(input), `${name}.json`); };