Skip to content

Scrub

Quick start

To install run:

npm i @framed/scrub

To validate an object:

import * as scrub from '@framed/scrub';

const personValidator = scrub.object({
  name: scrub.string({ transformString: ['trim', 'title'] }),
  age: scrub.number({ min: 18 }),
});

type PersonType = scrub.GetType<typeof personValidator>;

const validPerson: PersonType = {
  name: 'Homer Simpson',
  age: 39,
};

personValidator.validate(validPerson);
// { name: 'Homer Simpson', age: 39 }
const scrub = require('@framed/scrub');

const personValidator = scrub.object({
  name: scrub.string({ transformString: ['trim', 'title'] }),
  age: scrub.number({ min: 18 }),
});

const validPerson = {
  name: 'Homer Simpson',
  age: 39,
};

personValidator.validate(validPerson);
// { name: 'Homer Simpson', age: 39 }

Validators

Validators are setup during construction and can be modified using the same keys on the objects.

String

empty

If empty is true then the string may contain no characters. If not specified the string must contain a value.

Example: scrub.string({ empty: true }).

minLength

Specifies the minimum number of characters. If not specified the length is not checked.

Example: scrub.string({ minLength: 3 }).

maxLength

Specifies the maximum number of characters. If not specified the length is not checked.

Example: scrub.string({ maxLength: 10 }).

choices

An array of items which the value is allowed to be. If not specified the value is not checked.

Example: scrub.string({ choices: ['true', 'false'] }).

allowTypes

Specifies types that are not strings that will be converted. These types can be number, boolean, bigint or all. These types can also be use in array to select multiple. If not specified only strings are allowed.

Example: scrub.string({ allowTypes: 'all' }) or scrub.string({ allowTypes: ['number', 'bigint'] }).

transform

Transform the string before running the validation checks. The types of transformation can be: * trimStart - remove white space from the start of the string. * trimEnd - remove white space from the end of the string. * trim - remove white space from both the start and end. * upperCase - all characters will be capital letters. * lowerCase - all characters will be small letters. * title - the first letter of every word will be capitalized. * upperCaseFirst - only the first letter will be capitalized.

Transformations can be specified with as a string or as an array containing multiple entries. If not specified the string is not modified.

Example: scrub.string({ transform: 'trim' }) or scrub.string({ allowTypes: ['trim', 'title'] }).

Number

allowTypes

The only allowed type is 'string'. A string will be converted if it can be accurately converted using the validation rules specified.

If a long decimal is to be used it is a good idea to also set a precision as this will help in the conversion.

If this value is not specified only numbers are allowed.

Example: scrub.number({ allowTypes: 'string', precision: 4 }).

empty

If allowTypes is string and empty is true the number will not be defined. If not specified a number must be entered.

Example: scrub.number({ allowTypes: 'string', precision: 4, empty: true }).

min

Specifies the minimum number allowed. This field can either be: * An object containing both value and whether it is inclusive, or * A number which is the minimum value (inclusive).

These are described in the examples below. If this value is not specified the number can be any value.

Example: scrub.number({ min: 3 }) or scrub.number({ min: { value: 3, inclusive: false } }).

max

Specifies the maximum number allowed. This field can either be: * An object containing both value and whether it is inclusive, or * A number which is the maximum value (inclusive).

These are described in the examples below. If this value is not specified the number can be any value.

Example: scrub.number({ max: 10 }) or scrub.number({ max: { value: 10, inclusive: false } }).

choices

An array of items which the value is allowed to be. The default is any value is allowed.

Example: scrub.number({ choices: [2, 4, 6, 8] }).

precision

The maximum number of decimals. If this value is not specified then the number will be unchanged.

Example: scrub.number({ precision: 2 }).

Domain

Domain has all the string validation options.

allow

Specifies the types allowed: * domain - a domain name name as described in RFC1035 (eg: www.github.com). * ipv4 - IPv4 ip address (eg: 127.0.0.1). * ipv6 - IPv6 ip address (eg: ::1). * ip - both ipv4 and ipv6. * all - all of the above.

These types can also be use in array to select multiple. If not specified domains are allowed.

Example: scrub.domain({ allowTypes: 'all' }).

Email

allow

Specifies the types allowed: * domain - a domain name name as described in RFC1035 (eg: www.github.com). * ipv4 - IPv4 ip address (eg: 127.0.0.1). * ipv6 - IPv6 ip address (eg: ::1). * ip - both ipv4 and ipv6. * all - all of the above.

These types can also be use in array to select multiple. If not specified domains are allowed.

Example: scrub.email({ allowTypes: 'all' }).

URI

allow

Specifies the types allowed: * domain - a domain name name as described in RFC1035 (eg: www.github.com). * ipv4 - IPv4 ip address (eg: 127.0.0.1). * ipv6 - IPv6 ip address (eg: ::1). * ip - both ipv4 and ipv6. * all - all of the above.

These types can also be use in array to select multiple. If not specified all types are allowed.

Example: scrub.uri({ allowTypes: 'all' }).

allowedProtocols

The protocols which are allowed in the URI. If not specified any protocol is allowed.

Example: scrub.uri({ allowedProtocols: ['https'] }).

Password

Password has all the string validation options.

The default password validation is everything off. This is to allow the program to specify the default settings.

ignoreRequirementsIfLengthIsAtLeast

If the value is longer then the specified length, then the value is valid without looking at the other password specific requirements.

Example: scrub.example({ ignoreRequirementsIfLengthIsAtLeast: 12, requireLowerCase: true }).

requireLowerCase

If the value is true then a lowercase (or little character) is required. If not specified this check is skipped.

requireUpperCase

If the value is true then a lowercase (or little character) is required. If not specified this check is skipped.

requireNumber

If the value is true then a digit is required. If not specified this check is skipped.

requireSymbol

If the value is true then a symbol (such as '!') is required. If not specified this check is skipped.

Advanced

Conditional validation

See Custom Validation to perform conditional validation.

Custom validation

Inside the object validator is a callback customValidation which is called when each field in the object is validated.

This field allows you to update the validation before it is returned, in this method you can:

  • Add, update or remove errors
  • Modify cleaned values

The following shows an example where the field guardian is required if the age of the person is under 18.

import * as scrub from '@framed/scrub';

const personValidator = scrub.object({
  fields: {
    name: scrub.string({ transformString: ['trim', 'title'] }),
    age: scrub.number({ allowTypes: ['string'] }),
    guardian: scrub.string({ transformString: ['trim', 'title'], empty: true }),
  },
  customValidation: (state) => {
    if (state.cleanedFields.age < 18 && state.cleanedFields.guardian === '') {
      state.addError('Parent or guardian name is required if the person is under 18 years of age', 'guardian');
    }
  },
});

type PersonType = scrub.GetType<typeof personValidator>;
const validPerson: PersonType = {
  name: 'Homer Simpson',
  age: '39' as any,
  guardian: '',
};

console.log(personValidator.validate(validPerson));
// { name: 'Homer Simpson', age: 39 }

console.log(
  personValidator.validate(
    {
      name: 'Bart Simpson',
      age: '10' as any,
      guardian: '',
    },
    { throwOnFailure: false }
  )
);
// {
//   result: undefined,
//   success: false,
//   error: 'Object failed to validate',
//   fields: {
//     guardian: 'Parent or guardian name is required if the person is under 18 years of age'
//   }
// }
var scrub = require('@framed/scrub');

var personValidator = scrub.object({
  fields: {
    name: scrub.string({ transformString: ['trim', 'title'] }),
    age: scrub.number({ allowTypes: ['string'] }),
    guardian: scrub.string({ transformString: ['trim', 'title'], empty: true }),
  },
  customValidation: function (state) {
    if (state.cleanedFields.age < 18 && state.cleanedFields.guardian === '') {
      state.addError('Parent or guardian name is required if the person is under 18 years of age', 'guardian');
    }
  },
});

var validPerson = {
  name: 'Homer Simpson',
  age: '39',
  guardian: '',
};

console.log(personValidator.validate(validPerson));
// { name: 'Homer Simpson', age: 39 }

console.log(
  personValidator.validate(
    {
      name: 'Bart Simpson',
      age: '10',
      guardian: '',
    },
    { throwOnFailure: false }
  )
);
// {
//   result: undefined,
//   success: false,
//   error: 'Object failed to validate',
//   fields: {
//     guardian: 'Parent or guardian name is required if the person is under 18 years of age'
//   }
// }

Schema

To fetch an objects schema run the method validator.serialize() on any validator. This will create a JSON representation of the object.

Serialized objects may contain additional fields that were not passed by the user but are used for checks.

Serialization would be useful for: * Form validation - as you can fetch properties such as the field maximum length or if a field is required, * Database ORM - field maximum length, * Documentation - such as documenting an API, * etc.