https://www.npmjs.com/package/valleyed

Это относится к 2020 году, в разгар пандемии. Я только что изучил концепцию доменно-ориентированного дизайна и API композиции в Vue. Поэтому мне не терпелось объединить обе концепции в проекте Vue-Firebase, над которым я работал в то время.

import { BaseFactory } from '@modules/core'
import { isEmail, isLongerThan, isShorterThan, isString } from 'valleyed'
import { AuthUser } from '../entities/auth'

type Keys = { email: string, password: string }

export class EmailSigninFactory extends BaseFactory<null, AuthUser, Keys> {
   readonly rules = {
      email: { required: true, rules: [isEmail()] },
      password: { required: true, rules: [isString(), isLongerThan(5), isShorterThan(17)] }
   }
  
   reserved = []
  
   constructor () {
      super({ email: '', password: '' })
   }
  
   get email () {
      return this.values.email
   }
  
   set email (value: string) {
      this.set('email', value)
   }
  
   get password () {
      return this.values.password
   }
  
   set password (value: string) {
      this.set('password', value)
   }
  
   toModel = async () => {
      if (this.valid) {
         const { email, password } = this.validValues
         return { email, password }
      } else throw new Error('Validation errors')
   }
}

Мое понимание концепции привело меня к созданию фабричного класса, отвечающего за проверку формы с использованием шаблона построителя. Вы можете установить каждое свойство в форме по отдельности и, когда все будет удовлетворено, вы можете вызвать метод toModel для построения модели, которая представляет собой данные, которые отправляются на серверную часть или, в моем случае, в Firebase.

Как и следовало ожидать, во время «настройки» полей формы вам потребуется запустить некоторую логику проверки, чтобы убедиться, что устанавливаемое значение соответствует ожидаемому формату. Например, в приведенном выше примере кода вы ожидаете, что значение, установленное для поля электронной почты, будет отформатировано как действительный адрес электронной почты.

Мое путешествие по кроличьей норе библиотек проверки было довольно бесплодным, поскольку я не мог найти библиотеку проверки, которую можно было бы составить так легко, как я хотел. Поэтому, немного подумав, я решил создать свою библиотеку проверки, которая была бы легкой, легко настраиваемой, имела бы интуитивно понятный API, могла быть интегрирована в любое приложение javascript, будь то внешний или внутренний интерфейс, и имела бы прекрасную поддержку машинописного текста.

Конечный продукт был Valleyed. Пакет позволял пользователям проверять значения с помощью отдельных правил или составлять несколько правил вместе.

import { isEmail } from 'valleyed'

const emailRule = isEmail()

const validEmail = emailRule('[email protected]')
console.log(validEmail)
// { valid: true, errors: [], value: "[email protected]" }

const invalidEmail = emailRule('john-doe')
console.log(invalidEmail)
// { valid: false, errors: ["is not a valid email"], value: "john-doe" }
import { isEmail, isMinOf, isString, isNumber, Validator } from 'valleyed'

let validEmail = Validator.and(
 [[isEmail(), isMinOf(1)]]
)('[email protected]')

let validStringOrNumber = Validator.or(
 [[isString(), isMinOf(1)], [isNumber()]]
)(3)

console.log(validEmail)
// { valid: true, errors: [], value: "[email protected]" }

console.log(validStringOrNumber)
// { valid: true, errors: [], value: 3 }

Некоторые общие правила, поддерживаемые пакетом, включают:

Общие правила

  1. равно
import { isEqualTo } from 'valleyed'

const isEqualTo2 = isEqualTo(2)

const valid = isEqualTo2(2)

const invalid = isEqualTo2(3)

Это работает как для примитивных, так и для некоторых ссылочных типов. Поддерживаемые ссылочные типы включают массивы, объекты, наборы, карты, даты и т. д. Существует специальный алгоритм, который проверяет, являются ли два сравниваемых значения глубоко равными. Этот алгоритм экспортируется в класс «Differ».

import { Differ } from 'valleyed'

Differ.equal({ id: 1 }, { id: 1 }) // true

Однако, если равенство Differ не поддерживает ваш вариант использования, вы можете передать свою собственную функцию равенства в правило «isEqualTo».

import { isEqualTo } from 'valleyed'

const isEqualTo2 = isEqualTo({ id: 1, name: 'John' }, (validatingValue, compareValue) => {
 return validatingValue.id === compareValue.id
})

const valid = isEqualTo2({ id: 1, name: 'James' })

const invalid = isEqualTo2({ id: 2, name: 'John' })

2. не равно

Работает аналогично правилу isEqualTo, но проверяет неравенство

3. массив содержит

import { arrayContains } from 'valleyed'

const isInArrayOf1To5 = arrayContains([1,2,3,4,5])

const valid = isInArrayOf1To5(1)

const invalid = isInArrayOf1To5(10)

Подобно правилу isEqualTo, правило arrayContains принимает функцию равенства в качестве второго аргумента.

4. массив не содержит

Работает аналогично правилу arrayContains, но проверяет, что проверяемое значение не находится в массиве.

Правила строк

  1. isString
  2. isLengthOf
  3. isMinOf
  4. isMaxOf
  5. isEmail
  6. isUrl

Правила нумерации

  1. isNumber
  2. isInt
  3. больше чем
  4. isMoreThanOrEqualTo
  5. меньше чем
  6. isLessThanOrEqualTo

Правила массива

  1. isArray
  2. hasLengthOf
  3. hasMinOf
  4. hasMaxOf
  5. isArrayOf
import { isArrayOf, isString } from 'valleyed'

const isArrayOfStrings = isArrayOf((value) => isString()(value).valid)

const valid = isArrayOfStrings(['a', 'b', 'c'])

const invalid = isArrayOfStrings(['a', 1, 'b'])

Это правило проверяет, соответствует ли каждый элемент массива условию

Записи и карты

  1. isRecord

Запись — это в основном объект, в котором все его значения имеют один и тот же тип и контекст. Например, запись идентификаторов пользователей, сопоставленных с их полными именами, будет

import { isRecord, isString } from 'valleyed'

const userRecords = {
   1: 'John Doe',
   2: 'Alan Hughs',
   3: 'Mary Lamb'
}

const rule = isRecord((val) => isString(val).valid)

const valid = rule(userRecords)

const invalid = rule({ 1: true, 2: false, 3: null })

2. карта

Карта — это тип данных, построенный поверх обычных объектов. Основное различие между ними заключается в том, что карты могут иметь любой тип данных для ключей, в то время как ключи обычных объектов всегда неявно преобразуются в строки.

import { isMap, isString, isNumber } from 'valleyed'

const userMap = new Map([
   [1, 'John Doe'],
   [2, 'Alan Hughs'],
   [3, 'Mary Lamb']
])

const rule = isMap((key) => isNumber(key).valid,(val) => isString(val).valid)

const valid = rule(userMap)

const invalid = rule(new Map([
   [1, true],
   [2, false],
   [3, null]
]))

Даты/время

  1. время
import { isTime } from 'valleyed'

const rule = isTime()

let valid = rule(1679241498972)
valid = rule('2018-01-01T00:00:00.000Z')
valid = rule(new Date())

let invalid = rule([])
invalid = rule('')

Проверяемое значение передается в конструктор Date, и результатом является допустимый объект Date, значение является допустимым.

2. раньше, чем

Проверяет, встречается ли проверочное значение до или после сравниваемого значения. И значение проверки, и значение сравнения передаются в конструктор Date, и если какое-либо значение приводит к недопустимой дате, значение является недопустимым.

3. позже, чем

Проверяет, происходит ли проверочное значение после или на сравниваемом значении. И значение проверки, и значение сравнения передаются в конструктор Date, и если какое-либо значение приводит к недопустимой дате, значение является недопустимым.

Типы файлов

  1. isFile

Это правило проверяет, является ли ключ типа под значением допустимым поддерживаемым типом mime. Все поддерживаемые типы mime экспортируются под именем «fileMimeTypes».

import { isFile, fileMimeTypes } from 'valleyed'

const rule = isFile()

const valid = rule({ type: 'image/png' })

let invalid = rule(undefined)
invalid = rule({})
invalid = rule({ type: 'unknown mimetype' })

2. изображение

3. видео

4. аудио

Другие типы

  1. isUndefined
  2. нулевой
  3. isBoolean
  4. isInstanceOf

Для всех правил, поддерживаемых этим пакетом, сообщение об ошибке можно настроить, передав строку в качестве последнего аргумента в функцию, вызываемую для построения правила.

import { isString } from 'valleyed'

const rule = isString('custom error message')

const invalid = rule(2)
// { valid: false, value: 2, errors: ['custom error message'] }

Помимо правил проверки, пакет также экспортирует некоторые функции дезинфицирующего средства.

  1. капитализировать — делает заглавной строку переданную в нее
  2. stripHTML — удаляет переданную строку из всех тегов HTML, возвращая только текстовое содержимое между тегами HTML.
  3. trimToLength — обрезает переданную строку до указанной длины и добавляет «…» в конец обрезанной строки, если исходное значение было длиннее указанной длины.
  4. ExtractUrls — извлекает все URL-адреса, встроенные в переданную строку.
  5. shuffleArray — сортирует переданный массив в случайном порядке
  6. getRandomSample — получает n случайных выборок из переданного массива

и т. д.

Я надеюсь, что вы сможете найти применение этому пакету, и я всегда открыт для предложений и предложений. Со мной можно связаться по адресу [email protected] по электронной почте или https://twitter.com/kevinandeleven в Twitter.