chore(repo): initialize planarchy workspace
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import { z } from "zod";
|
||||
import { BlueprintTarget, FieldType } from "../types/enums.js";
|
||||
|
||||
export const FieldOptionSchema = z.object({
|
||||
value: z.string().min(1),
|
||||
label: z.string().min(1),
|
||||
color: z.string().optional(),
|
||||
});
|
||||
|
||||
export const FieldValidationSchema = z.object({
|
||||
min: z.number().optional(),
|
||||
max: z.number().optional(),
|
||||
minLength: z.number().int().optional(),
|
||||
maxLength: z.number().int().optional(),
|
||||
pattern: z.string().optional(),
|
||||
message: z.string().optional(),
|
||||
});
|
||||
|
||||
export const BlueprintFieldDefinitionSchema = z.object({
|
||||
id: z.string().min(1),
|
||||
label: z.string().min(1).max(200),
|
||||
key: z.string().min(1).max(100).regex(/^[a-z_][a-z0-9_]*$/, "Must be snake_case"),
|
||||
type: z.nativeEnum(FieldType),
|
||||
required: z.boolean().default(false),
|
||||
description: z.string().optional(),
|
||||
placeholder: z.string().optional(),
|
||||
defaultValue: z.unknown().optional(),
|
||||
options: z.array(FieldOptionSchema).optional(),
|
||||
validation: FieldValidationSchema.optional(),
|
||||
order: z.number().int().min(0),
|
||||
group: z.string().optional(),
|
||||
});
|
||||
|
||||
export const CreateBlueprintSchema = z.object({
|
||||
name: z.string().min(1).max(200),
|
||||
target: z.nativeEnum(BlueprintTarget),
|
||||
description: z.string().optional(),
|
||||
fieldDefs: z.array(BlueprintFieldDefinitionSchema).default([]),
|
||||
defaults: z.record(z.string(), z.unknown()).default({}),
|
||||
validationRules: z.array(z.object({
|
||||
field: z.string(),
|
||||
rule: z.enum(["required_if", "unique", "min", "max"]),
|
||||
params: z.unknown().optional(),
|
||||
message: z.string().optional(),
|
||||
})).default([]),
|
||||
});
|
||||
|
||||
export const UpdateBlueprintSchema = CreateBlueprintSchema.partial();
|
||||
|
||||
export type CreateBlueprintInput = z.infer<typeof CreateBlueprintSchema>;
|
||||
export type UpdateBlueprintInput = z.infer<typeof UpdateBlueprintSchema>;
|
||||
|
||||
/** Generate a Zod schema from blueprint field definitions at runtime */
|
||||
export function generateDynamicZodSchema(
|
||||
fieldDefs: z.infer<typeof BlueprintFieldDefinitionSchema>[],
|
||||
): z.ZodObject<Record<string, z.ZodTypeAny>> {
|
||||
const shape: Record<string, z.ZodTypeAny> = {};
|
||||
|
||||
for (const field of fieldDefs) {
|
||||
let fieldSchema: z.ZodTypeAny;
|
||||
|
||||
switch (field.type) {
|
||||
case FieldType.TEXT:
|
||||
case FieldType.TEXTAREA:
|
||||
case FieldType.URL:
|
||||
case FieldType.EMAIL:
|
||||
fieldSchema = z.string();
|
||||
if (field.validation?.minLength !== undefined) {
|
||||
fieldSchema = (fieldSchema as z.ZodString).min(field.validation.minLength);
|
||||
}
|
||||
if (field.validation?.maxLength !== undefined) {
|
||||
fieldSchema = (fieldSchema as z.ZodString).max(field.validation.maxLength);
|
||||
}
|
||||
if (field.type === FieldType.EMAIL) {
|
||||
fieldSchema = (fieldSchema as z.ZodString).email();
|
||||
}
|
||||
if (field.type === FieldType.URL) {
|
||||
fieldSchema = (fieldSchema as z.ZodString).url();
|
||||
}
|
||||
break;
|
||||
case FieldType.NUMBER:
|
||||
fieldSchema = z.number();
|
||||
if (field.validation?.min !== undefined) {
|
||||
fieldSchema = (fieldSchema as z.ZodNumber).min(field.validation.min);
|
||||
}
|
||||
if (field.validation?.max !== undefined) {
|
||||
fieldSchema = (fieldSchema as z.ZodNumber).max(field.validation.max);
|
||||
}
|
||||
break;
|
||||
case FieldType.BOOLEAN:
|
||||
fieldSchema = z.boolean();
|
||||
break;
|
||||
case FieldType.DATE:
|
||||
fieldSchema = z.coerce.date();
|
||||
break;
|
||||
case FieldType.SELECT:
|
||||
if (field.options && field.options.length > 0) {
|
||||
const values = field.options.map((o) => o.value) as [string, ...string[]];
|
||||
fieldSchema = z.enum(values);
|
||||
} else {
|
||||
fieldSchema = z.string();
|
||||
}
|
||||
break;
|
||||
case FieldType.MULTI_SELECT:
|
||||
if (field.options && field.options.length > 0) {
|
||||
const values = field.options.map((o) => o.value) as [string, ...string[]];
|
||||
fieldSchema = z.array(z.enum(values));
|
||||
} else {
|
||||
fieldSchema = z.array(z.string());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fieldSchema = z.unknown();
|
||||
}
|
||||
|
||||
if (!field.required) {
|
||||
fieldSchema = fieldSchema.optional();
|
||||
}
|
||||
|
||||
shape[field.key] = fieldSchema;
|
||||
}
|
||||
|
||||
return z.object(shape);
|
||||
}
|
||||
Reference in New Issue
Block a user