Библиотека Validator.js построена как набор чистых функций, работающих со строковыми значениями. Такая архитектура делает её гибкой для расширения, поскольку основная логика не скрыта внутри классов и не завязана на внутреннее состояние. Расширение функциональности в этом контексте означает добавление собственных валидаторов, создание обёрток над существующими функциями, композицию проверок и внедрение дополнительных правил обработки данных.
Ключевая особенность расширяемости заключается в том, что каждая функция библиотеки является независимой и может быть использована как строительный блок для более сложных проверок.
Наиболее распространённый способ расширения — написание собственных функций проверки, использующих базовые возможности Validator.js.
Простейшая форма кастомного валидатора выглядит как функция, которая принимает строку и возвращает булево значение:
function isCorporateEmail(email) {
if (!validator.isEmail(email)) {
return false;
}
return email.endsWith('@company.com');
}
Такой подход позволяет:
Более сложные валидаторы могут включать нормализацию данных перед проверкой:
function isStrongUsername(value) {
const normalized = validator.trim(value);
return (
validator.isLength(normalized, { min: 6, max: 20 }) &&
/^[a-zA-Z0-9_]+$/.test(normalized)
);
}
Validator.js хорошо подходит для функциональной композиции. Несколько проверок можно объединять в цепочки, формируя более сложные правила.
function validatePassword(password) {
return (
validator.isLength(password, { min: 10 }) &&
validator.matches(password, /[A-Z]/) &&
validator.matches(password, /[a-z]/) &&
validator.matches(password, /[0-9]/)
);
}
Для повышения гибкости часто используется подход с массивом правил:
const rules = [
v => validator.isLength(v, { min: 8 }),
v => validator.matches(v, /[A-Z]/),
v => validator.matches(v, /[0-9]/)
];
function runValidation(value, rules) {
return rules.every(fn => fn(value));
}
Такой стиль позволяет динамически формировать набор проверок в зависимости от контекста.
Расширение часто реализуется через создание обёрток, которые добавляют контекст или унифицируют поведение.
function validateAndNormalizeEmail(email) {
const normalized = validator.normalizeEmail(email);
return validator.isEmail(normalized) ? normalized : null;
}
Обёртки полезны для:
При увеличении количества правил имеет смысл структурировать их в отдельные модули.
// validators/email.js
export function isWorkEmail(email) {
return validator.isEmail(email) &&
email.split('@')[1] !== 'gmail.com';
}
// validators/password.js
export function isSecurePassword(value) {
return validator.isStrongPassword(value, {
minLength: 12,
minNumbers: 2,
minSymbols: 1
});
}
Такой подход обеспечивает:
Фабричный подход позволяет создавать параметризованные проверки:
function createLengthValidator(min, max) {
return function(value) {
return validator.isLength(value, { min, max });
};
}
const isUsernameValid = createLengthValidator(5, 15);
Это особенно полезно, когда одни и те же правила применяются к разным сущностям с разными ограничениями.
Validator.js возвращает булевы значения, поэтому обработка ошибок обычно выносится на уровень выше. Для расширения функциональности добавляется слой сообщений:
function validateAge(age) {
if (!validator.isInt(age, { min: 18 })) {
return {
valid: false,
error: 'Возраст должен быть не менее 18 лет'
};
}
return { valid: true };
}
Расширенные системы часто используют единый формат результата:
function result(valid, message = null) {
return { valid, message };
}
Декораторы позволяют модифицировать поведение существующих функций без изменения их исходного кода.
function withTrim(validatorFn) {
return function(value) {
return validatorFn(validator.trim(value));
};
}
const isTrimmedEmail = withTrim(validator.isEmail);
Подобный подход удобен для:
В сложных системах проверки зависят от состояния приложения или окружения.
function isValidUsername(value, context) {
if (context.role === 'admin') {
return validator.isLength(value, { min: 3 });
}
return validator.isLength(value, { min: 6 });
}
Контекст позволяет динамически изменять правила без дублирования кода.
Validator.js часто используется как часть цепочек обработки:
function pipeline(value, steps) {
return steps.reduce((acc, fn) => fn(acc), value);
}
const processEmail = pipeline(email, [
validator.trim,
validator.normalizeEmail
]);
Расширение функциональности в этом случае заключается в добавлении новых шагов в цепочку без изменения структуры системы.
Хотя библиотека не является объектно-ориентированной, её можно обернуть в слой сервисов:
const ValidatorService = {
isEmail(value) {
return validator.isEmail(value);
},
isCorporateEmail(value) {
return this.isEmail(value) && value.endsWith('@company.com');
}
};
Такой подход используется для:
В крупных приложениях удобно регистрировать валидаторы динамически:
const registry = {};
function registerValidator(name, fn) {
registry[name] = fn;
}
function validate(name, value) {
return registry[name](value);
}
registerValidator('email', validator.isEmail);
Это позволяет строить конфигурируемую систему проверок, где правила подключаются по мере необходимости.
Расширение функционала часто включает не только проверку, но и преобразование:
function validatePhone(value) {
const normalized = value.replace(/\s+/g, '');
return validator.isMobilePhone(normalized);
}
Такой подход снижает вероятность ошибок, связанных с форматом входных данных.
При усложнении логики проверки делятся на уровни:
function validateUser(data) {
const emailValid = validator.isEmail(data.email);
const passwordValid = validator.isStrongPassword(data.password);
const ageValid = validator.isInt(data.age, { min: 18 });
return emailValid && passwordValid && ageValid;
}
Расширение системы заключается в добавлении новых уровней без изменения существующих.
Паттерн стратегии позволяет переключать алгоритмы проверки:
const strategies = {
strict: value => validator.isLength(value, { min: 10 }),
relaxed: value => validator.isLength(value, { min: 5 })
};
function validate(value, mode) {
return strategies[mode](value);
}
Такой механизм упрощает поддержку разных сценариев использования.
Validator.js часто применяется для нормализации внешних источников:
function validateApiPayload(payload) {
return {
email: validator.normalizeEmail(payload.email),
name: validator.trim(payload.name),
age: validator.toInt(payload.age)
};
}
Это превращает библиотеку в инструмент не только проверки, но и подготовки данных к дальнейшей обработке.