gather-ts
Version:
A powerful code analysis and packaging tool designed for creating AI-friendly code representations for javascript and typescript projects.
235 lines • 9.21 kB
JavaScript
;
// src/utils/validation/Validator.ts
Object.defineProperty(exports, "__esModule", { value: true });
exports.Validator = void 0;
const errors_1 = require("@/errors");
const services_1 = require("@/types/services");
class Validator extends services_1.BaseService {
constructor(deps, options = {}) {
super();
this.deps = deps;
this.debug = options.debug || false;
}
async initialize() {
await super.initialize();
this.logDebug("Validator service initialized");
}
cleanup() {
this.logDebug("Validator service cleanup");
super.cleanup();
}
logDebug(message) {
if (this.debug) {
this.deps.logger.debug(message);
}
}
handleValidationError(fieldName, message, details) {
const error = new errors_1.ValidationError(message, details);
this.deps.logger.error(`Validation error for ${fieldName}: ${message}`);
throw error;
}
validate(value, fieldName, options = {}) {
this.checkInitialized();
this.logDebug(`Validating ${fieldName}`);
const result = {
isValid: true,
errors: [],
warnings: [],
};
try {
// Handle optional fields
if (value === undefined || value === null) {
if (!options.optional) {
result.errors.push(`${fieldName} is required`);
result.isValid = false;
}
return result;
}
// Type validation
if (options.type && typeof value !== options.type) {
result.errors.push(`${fieldName} must be of type ${options.type}, got ${typeof value}`);
result.isValid = false;
return result;
}
// Type-specific validations
if (typeof value === "string") {
this.validateString(value, fieldName, options, result);
}
if (typeof value === "number") {
this.validateNumber(value, fieldName, options, result);
}
if (Array.isArray(value)) {
this.validateArray(value, fieldName, options, result);
}
if (this.isObject(value)) {
this.validateObject(value, fieldName, options, result);
}
// Custom validation
if (options.customValidator) {
this.runCustomValidator(value, fieldName, options.customValidator, result);
}
}
catch (error) {
result.errors.push(error instanceof Error ? error.message : String(error));
result.isValid = false;
this.deps.logger.error(`Validation error for ${fieldName}: ${error instanceof Error ? error.message : String(error)}`);
}
this.logDebug(`Validation result for ${fieldName}: ${result.isValid ? "valid" : "invalid"}`);
return result;
}
validateString(value, fieldName, options, result) {
if (!options.allowEmpty && value.trim() === "") {
result.errors.push(`${fieldName} cannot be empty`);
result.isValid = false;
return;
}
if (options.minLength !== undefined && value.length < options.minLength) {
result.errors.push(`${fieldName} must be at least ${options.minLength} characters long`);
result.isValid = false;
}
if (options.maxLength !== undefined && value.length > options.maxLength) {
result.errors.push(`${fieldName} cannot exceed ${options.maxLength} characters`);
result.isValid = false;
}
if (options.pattern && !options.pattern.test(value)) {
result.errors.push(`${fieldName} has an invalid format`);
result.isValid = false;
}
}
validateNumber(value, fieldName, options, result) {
if (options.min !== undefined && value < options.min) {
result.errors.push(`${fieldName} must be at least ${options.min}`);
result.isValid = false;
}
if (options.max !== undefined && value > options.max) {
result.errors.push(`${fieldName} cannot exceed ${options.max}`);
result.isValid = false;
}
if (options.integer && !Number.isInteger(value)) {
result.errors.push(`${fieldName} must be an integer`);
result.isValid = false;
}
}
validateArray(value, fieldName, options, result) {
if (options.minLength !== undefined && value.length < options.minLength) {
result.errors.push(`${fieldName} must contain at least ${options.minLength} items`);
result.isValid = false;
}
if (options.maxLength !== undefined && value.length > options.maxLength) {
result.errors.push(`${fieldName} cannot contain more than ${options.maxLength} items`);
result.isValid = false;
}
if (options.arrayType) {
const invalidItems = value.filter((item) => typeof item !== options.arrayType);
if (invalidItems.length > 0) {
result.errors.push(`All items in ${fieldName} must be of type ${options.arrayType}`);
result.isValid = false;
}
}
}
validateObject(value, fieldName, options, result) {
if (options.requiredFields) {
const missingFields = options.requiredFields.filter((field) => !(field in value));
if (missingFields.length > 0) {
result.errors.push(`${fieldName} is missing required fields: ${missingFields.join(", ")}`);
result.isValid = false;
}
}
}
validatePath(path, context) {
if (!path || typeof path !== "string") {
throw new errors_1.ValidationError(`Invalid ${context} path`, { path });
}
// Check for invalid characters in path
const invalidChars = /[<>:"|?*]/g;
if (invalidChars.test(path)) {
throw new errors_1.ValidationError(`${context} path contains invalid characters`, {
path,
invalidChars: '<>:"|?*',
});
}
// Check for relative path navigation
if (path.includes("../") || path.includes("..\\")) {
throw new errors_1.ValidationError(`${context} path cannot contain relative navigation`, { path });
}
// Log debug info
this.logDebug(`Validated path for ${context}: ${path}`);
}
runCustomValidator(value, fieldName, validator, result) {
try {
const customResult = validator(value);
if (!customResult) {
result.errors.push(`${fieldName} failed custom validation`);
result.isValid = false;
}
}
catch (error) {
result.errors.push(`Custom validation error for ${fieldName}: ${error instanceof Error ? error.message : String(error)}`);
result.isValid = false;
}
}
// Type Guard Implementations
isString(value) {
return typeof value === "string";
}
isNumber(value) {
return typeof value === "number" && !isNaN(value);
}
isBoolean(value) {
return typeof value === "boolean";
}
isObject(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
isArray(value) {
return Array.isArray(value);
}
isDate(value) {
return value instanceof Date && !isNaN(value.getTime());
}
// Helper Methods
validateNotEmpty(value, fieldName) {
const result = this.validate(value, fieldName, { optional: false });
if (!result.isValid) {
this.handleValidationError(fieldName, result.errors[0]);
}
return value;
}
validateType(value, expectedType, fieldName) {
const result = this.validate(value, fieldName, { type: expectedType });
if (!result.isValid) {
this.handleValidationError(fieldName, result.errors[0]);
}
}
validateRange(value, min, max, fieldName) {
const result = this.validate(value, fieldName, {
type: "number",
min,
max,
});
if (!result.isValid) {
this.handleValidationError(fieldName, result.errors[0]);
}
}
validateEnum(value, enumValues, fieldName) {
const result = this.validate(value, fieldName, {
type: "string",
customValidator: (val) => enumValues.includes(val),
});
if (!result.isValid) {
this.handleValidationError(fieldName, `${fieldName} must be one of: ${enumValues.join(", ")}`, { value, allowedValues: enumValues });
}
return value;
}
validatePattern(value, pattern, fieldName) {
const result = this.validate(value, fieldName, {
type: "string",
pattern,
});
if (!result.isValid) {
this.handleValidationError(fieldName, result.errors[0]);
}
}
}
exports.Validator = Validator;
//# sourceMappingURL=Validator.js.map