@codervisor/devlog-core
Version:
Core devlog management functionality
120 lines (119 loc) • 4.15 kB
JavaScript
/**
* Project validation schemas using Zod
*
* This module provides runtime validation for project-related data at the business logic layer.
* It ensures data integrity and business rule compliance across all entry points.
*/
import { z } from 'zod';
/**
* Project Settings validation schema
*/
export const ProjectSettingsSchema = z.object({
defaultPriority: z.enum(['low', 'medium', 'high', 'critical']).optional(),
theme: z.string().optional(),
autoArchiveDays: z.number().min(1).max(365).optional(),
availableTags: z.array(z.string()).optional(),
customSettings: z.record(z.any()).optional(),
});
/**
* Project creation request schema (excludes auto-generated fields)
*/
export const CreateProjectRequestSchema = z.object({
name: z.string()
.min(1, 'Project name is required')
.max(100, 'Project name must be less than 100 characters')
.regex(/^[a-zA-Z0-9\s\-_]+$/, 'Project name can only contain letters, numbers, spaces, hyphens, and underscores'),
description: z.string()
.max(500, 'Description must be less than 500 characters')
.optional(),
repositoryUrl: z.string()
.url('Repository URL must be a valid URL')
.optional()
.or(z.literal('')), // Allow empty string
settings: ProjectSettingsSchema.optional(),
});
/**
* Project update request schema (all fields optional)
*/
export const UpdateProjectRequestSchema = z.object({
name: z.string()
.min(1, 'Project name is required')
.max(100, 'Project name must be less than 100 characters')
.regex(/^[a-zA-Z0-9\s\-_]+$/, 'Project name can only contain letters, numbers, spaces, hyphens, and underscores')
.optional(),
description: z.string()
.max(500, 'Description must be less than 500 characters')
.optional()
.or(z.literal('')), // Allow empty string to clear description
repositoryUrl: z.string()
.url('Repository URL must be a valid URL')
.optional()
.or(z.literal('')), // Allow empty string to clear URL
settings: ProjectSettingsSchema.optional(),
});
/**
* Project ID parameter schema
*/
export const ProjectIdSchema = z.object({
id: z.number().int().positive('Project ID must be a positive integer'),
});
/**
* Validation functions for business logic layer
*/
export class ProjectValidator {
/**
* Validate project creation data
*/
static validateCreateRequest(data) {
const result = CreateProjectRequestSchema.safeParse(data);
if (result.success) {
return { success: true, data: result.data };
}
return {
success: false,
errors: result.error.errors.map(err => `${err.path.join('.')}: ${err.message}`),
};
}
/**
* Validate project update data
*/
static validateUpdateRequest(data) {
const result = UpdateProjectRequestSchema.safeParse(data);
if (result.success) {
return { success: true, data: result.data };
}
return {
success: false,
errors: result.error.errors.map(err => `${err.path.join('.')}: ${err.message}`),
};
}
/**
* Validate project ID
*/
static validateProjectId(id) {
const result = ProjectIdSchema.safeParse({ id });
if (result.success) {
return { success: true, data: result.data.id };
}
return {
success: false,
errors: result.error.errors.map(err => `${err.path.join('.')}: ${err.message}`),
};
}
/**
* Business rule validation - check for duplicate project names
*/
static async validateUniqueProjectName(name, excludeId, checkFunction) {
if (!checkFunction) {
return { success: true }; // Skip if no check function provided
}
const isDuplicate = await checkFunction(name, excludeId);
if (isDuplicate) {
return {
success: false,
error: `Project with name "${name}" already exists`
};
}
return { success: true };
}
}