2026-08-15 18:37:30 +02:00
|
|
|
import { z } from "zod";
|
|
|
|
|
import type { ScriptConfig, VariableConfig } from "../config/schema";
|
|
|
|
|
|
|
|
|
|
function fieldSchema(variable: VariableConfig): z.ZodTypeAny {
|
|
|
|
|
let field: z.ZodTypeAny;
|
|
|
|
|
|
|
|
|
|
switch (variable.type) {
|
|
|
|
|
case "string": {
|
|
|
|
|
let s = z.string();
|
2026-08-16 00:06:39 +02:00
|
|
|
// `required` alone has to reject "" even when the author didn't set an explicit
|
|
|
|
|
// minLength - otherwise an empty string satisfies a bare z.string() and the run starts
|
|
|
|
|
// with a "required" field effectively unset.
|
|
|
|
|
const minLength =
|
|
|
|
|
variable.minLength ?? (variable.required ? 1 : undefined);
|
|
|
|
|
if (minLength !== undefined) s = s.min(minLength);
|
2026-08-15 18:37:30 +02:00
|
|
|
if (variable.maxLength !== undefined) s = s.max(variable.maxLength);
|
|
|
|
|
if (variable.pattern) s = s.regex(new RegExp(variable.pattern));
|
|
|
|
|
field = s;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "number": {
|
|
|
|
|
let n = z.number();
|
|
|
|
|
if (variable.min !== undefined) n = n.min(variable.min);
|
|
|
|
|
if (variable.max !== undefined) n = n.max(variable.max);
|
|
|
|
|
field = n;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "boolean":
|
|
|
|
|
field = z.boolean();
|
|
|
|
|
break;
|
|
|
|
|
case "enum":
|
|
|
|
|
field = z.enum(variable.choices as [string, ...string[]]);
|
|
|
|
|
break;
|
2026-08-16 00:06:39 +02:00
|
|
|
case "multiselect": {
|
|
|
|
|
let arr = z.array(z.enum(variable.choices as [string, ...string[]]));
|
|
|
|
|
if (variable.required) arr = arr.min(1);
|
|
|
|
|
field = arr;
|
2026-08-15 18:37:30 +02:00
|
|
|
break;
|
2026-08-16 00:06:39 +02:00
|
|
|
}
|
2026-08-15 18:37:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!variable.required) {
|
|
|
|
|
field = field.optional().or(z.literal(""));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Builds one Zod object schema from a list of variable definitions - the single source of truth
|
|
|
|
|
* imported by both the client form resolver and the server-side run-creation handler. */
|
|
|
|
|
export function buildVariableSchemaFromList(
|
|
|
|
|
variables: readonly VariableConfig[],
|
|
|
|
|
) {
|
|
|
|
|
const shape: Record<string, z.ZodTypeAny> = {};
|
|
|
|
|
for (const variable of variables) {
|
|
|
|
|
shape[variable.name] = fieldSchema(variable);
|
|
|
|
|
}
|
|
|
|
|
return z.object(shape);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function buildVariableSchema(script: ScriptConfig) {
|
|
|
|
|
return buildVariableSchemaFromList(script.variables);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type VariableValues = Record<string, unknown>;
|