Расширение функционала библиотеки

Библиотека 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)
  };
}

Это превращает библиотеку в инструмент не только проверки, но и подготовки данных к дальнейшей обработке.