/**
* Parameter Validator Implementation
* Provides comprehensive parameter validation for managers
*/
import { WordPressAPIError } from "@/types/client.js";
import type { ParameterValidator } from "@/client/managers/interfaces/ManagerInterfaces.js";
export class ParameterValidatorImpl implements ParameterValidator {
/**
* Validate required parameters are present
*/
validateRequired(params: Record<string, unknown>, requiredFields: string[]): void {
for (const field of requiredFields) {
if (params[field] === undefined || params[field] === null) {
throw new WordPressAPIError(`Missing required parameter: ${field}`, 400, "missing_parameter");
}
}
}
/**
* Validate parameter types and formats
*/
validateParameters<T>(params: unknown, schema?: unknown): T {
if (params === null || params === undefined) {
throw new WordPressAPIError("Parameters cannot be null or undefined", 400, "invalid_parameters");
}
// If no schema provided, return params as-is with type assertion
if (!schema) {
return params as T;
}
// Basic runtime validation (can be extended with schema validation libraries)
if (typeof params !== "object") {
throw new WordPressAPIError("Parameters must be an object", 400, "invalid_parameters");
}
return params as T;
}
/**
* Validate string parameters
*/
validateString(
value: unknown,
fieldName: string,
options?: {
required?: boolean;
minLength?: number;
maxLength?: number;
pattern?: RegExp;
},
): string {
if (options?.required && (value === undefined || value === null || value === "")) {
throw new WordPressAPIError(`${fieldName} is required`, 400, "missing_parameter");
}
if (value === undefined || value === null) {
return "";
}
if (typeof value !== "string") {
throw new WordPressAPIError(`${fieldName} must be a string`, 400, "invalid_parameter_type");
}
if (options?.minLength && value.length < options.minLength) {
throw new WordPressAPIError(
`${fieldName} must be at least ${options.minLength} characters`,
400,
"parameter_too_short",
);
}
if (options?.maxLength && value.length > options.maxLength) {
throw new WordPressAPIError(
`${fieldName} must be no more than ${options.maxLength} characters`,
400,
"parameter_too_long",
);
}
if (options?.pattern && !options.pattern.test(value)) {
throw new WordPressAPIError(`${fieldName} format is invalid`, 400, "invalid_parameter_format");
}
return value;
}
/**
* Validate numeric parameters
*/
validateNumber(
value: unknown,
fieldName: string,
options?: {
required?: boolean;
min?: number;
max?: number;
integer?: boolean;
},
): number {
if (options?.required && (value === undefined || value === null)) {
throw new WordPressAPIError(`${fieldName} is required`, 400, "missing_parameter");
}
if (value === undefined || value === null) {
return 0;
}
const numValue = typeof value === "string" ? parseFloat(value) : Number(value);
if (isNaN(numValue)) {
throw new WordPressAPIError(`${fieldName} must be a valid number`, 400, "invalid_parameter_type");
}
if (options?.integer && !Number.isInteger(numValue)) {
throw new WordPressAPIError(`${fieldName} must be an integer`, 400, "invalid_parameter_type");
}
if (options?.min !== undefined && numValue < options.min) {
throw new WordPressAPIError(`${fieldName} must be at least ${options.min}`, 400, "parameter_too_small");
}
if (options?.max !== undefined && numValue > options.max) {
throw new WordPressAPIError(`${fieldName} must be no more than ${options.max}`, 400, "parameter_too_large");
}
return numValue;
}
/**
* Validate array parameters
*/
validateArray<T>(
value: unknown,
fieldName: string,
options?: {
required?: boolean;
minLength?: number;
maxLength?: number;
itemValidator?: (item: unknown) => T;
},
): T[] {
if (options?.required && (value === undefined || value === null)) {
throw new WordPressAPIError(`${fieldName} is required`, 400, "missing_parameter");
}
if (value === undefined || value === null) {
return [];
}
if (!Array.isArray(value)) {
throw new WordPressAPIError(`${fieldName} must be an array`, 400, "invalid_parameter_type");
}
if (options?.minLength && value.length < options.minLength) {
throw new WordPressAPIError(
`${fieldName} must contain at least ${options.minLength} items`,
400,
"array_too_short",
);
}
if (options?.maxLength && value.length > options.maxLength) {
throw new WordPressAPIError(
`${fieldName} must contain no more than ${options.maxLength} items`,
400,
"array_too_long",
);
}
if (options?.itemValidator) {
try {
return value.map((item, index) => {
try {
return options.itemValidator!(item);
} catch (error) {
throw new WordPressAPIError(
`${fieldName}[${index}] validation failed: ${getErrorMessage(error)}`,
400,
"array_item_invalid",
);
}
});
} catch (error) {
if (error instanceof WordPressAPIError) {
throw error;
}
throw new WordPressAPIError(
`${fieldName} validation failed: ${getErrorMessage(error)}`,
400,
"array_validation_failed",
);
}
}
return value as T[];
}
/**
* Validate WordPress ID parameters
*/
validateWordPressId(value: unknown, fieldName: string = "id"): number {
const id = this.validateNumber(value, fieldName, {
required: true,
min: 1,
integer: true,
});
return id;
}
}
// Helper function to get error message
function getErrorMessage(error: unknown): string {
if (error instanceof Error) {
return error.message;
}
return String(error);
}