/** * Domain Value Object: LeagueDescription * * Represents a valid league description with validation rules. */ import type { ValueObject } from '@core/shared/domain/ValueObject'; import { RacingDomainValidationError } from '../errors/RacingDomainError'; export interface LeagueDescriptionValidationResult { valid: boolean; error?: string; } export const LEAGUE_DESCRIPTION_CONSTRAINTS = { minLength: 20, maxLength: 1000, recommendedMinLength: 50, } as const; export interface LeagueDescriptionProps { value: string; } export class LeagueDescription implements ValueObject { readonly value: string; private constructor(value: string) { this.value = value; } /** * Validate a league description without creating the value object */ static validate(value: string): LeagueDescriptionValidationResult { const trimmed = value?.trim() ?? ''; if (!trimmed) { return { valid: false, error: 'Description is required — help drivers understand your league' }; } if (trimmed.length < LEAGUE_DESCRIPTION_CONSTRAINTS.minLength) { return { valid: false, error: `Description must be at least ${LEAGUE_DESCRIPTION_CONSTRAINTS.minLength} characters — tell drivers what makes your league special`, }; } if (trimmed.length > LEAGUE_DESCRIPTION_CONSTRAINTS.maxLength) { return { valid: false, error: `Description must be ${LEAGUE_DESCRIPTION_CONSTRAINTS.maxLength} characters or less`, }; } return { valid: true }; } /** * Check if description meets recommended length for better engagement */ static isRecommendedLength(value: string): boolean { const trimmed = value?.trim() ?? ''; return trimmed.length >= LEAGUE_DESCRIPTION_CONSTRAINTS.recommendedMinLength; } /** * Create a LeagueDescription from a string value */ static create(value: string): LeagueDescription { const validation = this.validate(value); if (!validation.valid) { throw new RacingDomainValidationError(validation.error ?? 'Invalid league description'); } return new LeagueDescription(value.trim()); } get props(): LeagueDescriptionProps { return { value: this.value }; } /** * Try to create a LeagueDescription, returning null if invalid */ static tryCreate(value: string): LeagueDescription | null { const validation = this.validate(value); if (!validation.valid) { return null; } return new LeagueDescription(value.trim()); } toString(): string { return this.value; } equals(other: ValueObject): boolean { return this.props.value === other.props.value; } }