Валидация строк с validate.it.js

в 8:43, , рубрики: contributing, javascript, javascript library, JS, open source, validation, validator

Если вспомнить все ТЗ с описаниями валидации полей — они всегда выглядили примерно так:

  • не должно быть короче 6 символов
  • не должно превышать 12 символов
  • должно включать только латинские символы, цифры и знак подчёркивания

Требования часто приходят набором простых однозначных фраз. А мы, программисты, переводим эти требования в код.

Можно превращать их в одно ультимативное регулярное выражение, вроде

const validateLogin = login => /^[a-zA-z_d]{6,12}$/.test(login);

Но лучше писать более простые функций которые легче читать и связывать с непосредственным ТЗ:

const charMatch = new RegExp('^[a-zA-Z_0-9]*$');
const validateLogin = login => {
    if (login.length < 6) return false;
    if (login.length > 12) return false;
    if (!charMatch.test(login)) return false;
    return true;
};

А что если ещё сильнее упростить этот код до чего-то вроде:

const validateLogin = login => 
  validate(login)
    .notLessThan(6)
    .notLongerThan(12)
    .hasOnly(['a-z','A-Z','0-9','_']);


Основная идея заключается в том, что требования к валидации зачастую можно разложить на список независимых типичных утверждений. А эти утвержджени (asserts) можно собрать в коллекцию и переиспользовать.

Именно этим и занимается библиотека validate.it.js. Ядро которой не превышает и ста строк и делает не так уж много:

  • позволяет вызывать assert'ы цепочно
  • собирает и обрабатывает результаты

Вышеописанное значит, что выполнив код вроде этого:

validate('Pa$$w0rd')
  .hasLettersLatin()
  .hasNumbers()
  .has("!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+");

Вы получите вот такой результат.

{
  ok: true,
  base: 'Pa$$w0rd',
  asserts: ['hasLettersLatin', 'hasNumbers', 'has'],
  errors: []
}

Думаю это и так очевидно, но немного распишу

  • ok bool — статус валидации
    • true — валидация прошла успешно
    • false — валидация провалена
  • base string — валидируемая строка
  • asserts array — список имён вызванных assert'ов в порядке очерёдности их вызова
  • errors array — массив отчётов в формате Validation Report всех провалившихся assert'ов

Вот пример провалившейся валидации

validate('bob')
  .hasLettersLatin()
  .hasNumbers();
// -->
{
  ok: false,
  base: 'bob',
  asserts: ['hasLettersLatin', 'hasNumbers'],
  errors: [
    {
      path: [],
      rule: 'hasNumbers',
      details: {
        string: 'bob',
        subStrings: ["1","2","3","4","5","6","7","8","9","0"],
        found: false,
        message: '"bob" has no numbers'
      }
    }
  ]
}

Эта простая идея позволяет писать код валидации максимально приближённым к требованиям. При этом сами assert'ы получаются очень простыми и являются чистыми функциями. Их легко поддерживать, тестировать, и добавлять новые.

Кстати да, если вам не хватает какого-то assert'а — вы легко можете на-лету добавить его через @static .extend или использовать assert .eval.

Но не жадничайте своих assert'ов сообществу. Станьте контрибьютером!

Контрибьютерам

А теперь сюрприз. Самих assert'ов в библиотеке ещё практически и нет. Только парочка базовых вроде .has, .match, .eval и ещё немного для примеров. Нету даже тех, которые я использовал в листингах этого поста. Всё дело в том, что мне хотелось привлечь внимание к идее, а не к реализации.

Более того, я считаю, что моё видение необходимых assert'ов может сильно отличаться от видения сообщества. И, делая этот инструмент "под себя" я могу сделать его неудобным для других JS разработчиков. И у меня возникла идея — привлечь к созданию этого инструмента JS сообщество. Что бы самому ничего не делать он покрывал потребности сообщества, а не мои собственные.

I need you

Я приглашаю JS разработчиков стать контрибьютерами validate.it.js.
Всех кто хочет контрибьютить в опенсорс, но не знает с какого проекта начать.
Всех кто хочет сделать для себя и для всего сообщества удобный инструмент валидации.

Вместе мы сможем наполнить коллекцию реально необходимыми всем нам assert'ами.

При этом контрибьютером может быть разработчик любого уровня. Ведь кто-то захочет заняться валидацией по длине строки, а кому-то, например, интереснее реализовывать проверку на соответствие даты всем вариантам стандарта ISO 8601.

К pull-request'ам предъявляются весьма мягкие требования:

  • наличие тестов
  • наличие описания — что бы вставить его в раздел с перечнем assert'ов.

Validation Report

Кстати о вышеупомянутых VR которыми наполняется массив .errors в случае провалившихся assert'ов. Я искал какой-то стандарт для представления ошибок валидации. И по своему опыту знал, что банального true/false и даже null/'error message' недостаточно. И судя по всему, такого стандарта на сегодняшний день нету.

Зато есть замечательная идея читателя rumkin

"Универсальный интерфейс отчётов валидации" — @rumkin / Validation Report. git

Это простой DTO, который позволяет передать максимально подробную информацию о причинах провала валидации. Состоит из:

  • path array — местоположение объекта проверки. В контексте валидации строк — это всегда пустой массив [].
  • rule string — имя assert'а или правило по которому проводилась валидация.
  • details object — детали или описание в "машино-понятном виде" причины провала валидации. У этого параметра нету чётко-стандартизированный структуры, кроме одного поля:
    • details.message string — описание в "человеко-понятном виде". Это не стандартное для VR поле, но в рамках данного проекта оно обязательно.

Пример:

{
  path: [],
  rule: 'notLongerThen',
  details: {
    string: 'markopolo',
    length: 9,
    max: 6,
    message: '"markopolo" longer then 6 characters'
  }
}

rumkin, кстати, написал небольшой тул для генерации Validation Report'ов. но ради 0Dependecy я не использую конкретно эту реализацию. Благо генерация VR достаточно простая задача.

Будет здорово, если VR однажды станут стандартом, хотя бы локальным.

P.S.

Не стесняйтесь задавать вопросы — буду только рад расширить contributer's guide или ридми проекта.

Автор: titulusdesiderio

Источник

Поделиться

* - обязательные к заполнению поля