@fczbkk/config-mask

Helper that takes care of validating, sanitizing and coercing of complex config objects.

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
@fczbkk/config-mask
101.16.07 years ago8 years agoMinified + gzip package size for @fczbkk/config-mask in KB

Readme

Config Mask
Helper that takes care of validating, sanitizing and coercing of complex config objects.
npm npm David Travis

How to use

Install the library via NPM:
npm install @fczbkk/config-mask --save

Then use in your project like this:
import ConfigMask from '@fczbkk/config-mask';

Simple value

The simplest use is a coercion of input value.
var numeric_value = new ConfigMask({
  type: 'number',
  default: 0
});

// use default value when input is missing
numeric_value.sanitze();  // 0

// use default value when input is invalid
numeric_value.sanitize('xxx');  // 0

// use valid value
numeric_value.sanitize(100);  // 100

// convert value to expected type if possible
numeric_value.sanitize('100');  // 100

Any value

You can use type any to accept any type of input. It will not check the type nor sanitize it to any specific type.
var any_value = new ConfigMask({
  type: 'any'
});

any_value.sanitize(); // undefined
any_value.sanitize('aaa') // 'aaa'
any_value.sanitize(123) // '123'

You can still use any other options. For example default value, which will be used when input is undefined:
var any_value = new ConfigMask({
  type: 'any',
  default: 'n/a'
});

any_value.sanitize(); // 'n/a'
any_value.sanitize('aaa') // 'aaa'

Or you can use parser to transform input value:
var any_value = new ConfigMask({
  type: 'any',
  parse: function (input) {return typeof input;}
});

any_value.sanitize(); // 'undefined'
any_value.sanitize('aaa') // 'string'

Set

You can define set of valid values that can be used.
var set_value = new ConfigMask({
  type: 'set',
  values: ['aaa', 'bbb'],
  default: 'aaa'
});

// use valid value
set_value.sanitize('aaa'); // 'aaa'

// use default value on missing or invalid input
set_value.sanitize(); // 'aaa'
set_value.sanitize('xxx'); // 'aaa'

If you don't set default value, first of the valid values will be used:
var set_value = new ConfigMask({
  type: 'set',
  values: ['aaa', 'bbb']
});

set_value.sanitize(); // 'aaa'

List

Same as set, but for lists of values from defined set.
var list_value = new ConfigMask({
  type: 'list',
  values: ['aaa', 'bbb']
});

// valid values are fine, invalid ones are filtered out
list_value.sanitize(['aaa', 'xxx', 'bbb']); // ['aaa', 'bbb']

// single value is converted to array
list_value.sanitize('aaa'); // ['aaa']

// default value is always empty array
list_value.sanitize(); // []

List of...

Type list_of will produce an array with values of specific type.
  • You can use subtype property to define type of values in array.
  • You can use submask property to define ConfigMask that will be applied to values in array.
  • If both subtype and submask properties are defined, submask will be used.
  • If neither subtype nor submask property is defined, the array will accept values of any types.

var list_of_strings = new ConfigMask({
  type: 'list_of',
  subtype: 'text'
});
list_of_strings.sanitize(['aaa', null, 123]); // ['aaa', '', '123']

var list_of_objects = new ConfigMask({
  type: 'list_of',
  submask: {
    type: 'object',
    properties: {
      value: 'number',
      unit: 'text'
    },
    default: {
      value: 0,
      unit: 'px'
    }
  }
});
list_of_objects.sanitize([{value: 10, unit: 'cm'}, 'xxx']);
// [{value: 10, unit: 'cm'}, {value: 0, unit: 'px'}]

You can use filter property to define function for filtering out unwanted values.
var list_of_short_strings = new ConfigMask({
  type: 'list_of',
  subtype: 'text',
  filter: function (input) {return input.length <= 3;}
});
list_of_short_strings.sanitize(['aaa', 'abcdefgh', 'bbb']); // ['aaa', 'bbb']

Custom value types

You can write your own value types, using Coerce.
var array_of_strings = new ConfigMask({
  type: {
    string: function (input) {
      return [input];
    },
    array: function (input) {
      return input.map(function (item) {
        return item.toString();
      })
    }
  },
  default: []
});

array_of_strings.sanitize(); // []
array_of_strings.sanitize('aaa'); // ['aaa']
array_of_strings.sanitize(['aaa', 'bbb']); // ['aaa', 'bbb']

Custom validation

You can create masks with very specific rules using custom validation method.
var positive_number = new ConfigMask({
  type: 'number',
  validate: function (input) {return number > 0;},
  default: 1
});
positive_number.sanitize(10); // 10
positive_number.sanitize(-10); // 1 (default value)

To simplify debugging or error reporting, you can use on_invalid method. It will be called when sanitizing the input and it will receive the input as parameter.
var positive_number = new ConfigMask({
  type: 'number',
  validate: function (input) {return number > 0;},
  on_invalid: function (input) {
    console.log('Only positive numbers allowed. You have used ' + input + '.');
  },
  default: 1
});

In some cases, it may be helpful to validate the result after it has been sanitized. For example when dealing with complex objects with various sub-properties, where the end result of sanitation may depend on results of sanitation of properties.
var value_with_unit = ConfigMask({
  type: 'object',
  properties: {
    value: {type: 'number'},
    unit: {type: 'string'}
  },
  default: null,
  validate_after: function (input) {
    // if either `value` or `unit` is not set, sanitize to `nul` (default value)
    return input.value !== 0 && value.unit !== '';
  }
});

Simple objects

You can simply set the value to be an object:
var my_object = new ConfigMask({
  type: 'object'
});

my_object.sanitize(); // {}
my_object.sanitize('aaa'); // {}
my_object.sanitize({aaa: 'bbb'}); // {aaa: 'bbb'}

You can define a list of properties that the resulting object should have. Properties not on the list will be ignored. Missing properties will be added with undefined value:
var person_name = new ConfigMask({
  type: 'object',
  properties: ['first_name', 'last_name']
});

var sanitized_name = person_name.sanitize({
  first_name: 'John',
  occupation: 'programmer'
});

sanitized_name.first_name; // 'John'
sanitized_name.last_name; // undefined
sanitized_name.occupation; // undefined (ignored)

Complex objects

This is why I created ConfigMask. Sanitize complex configuration objects without going through all the properties and checking them manually.
var value_config = {
  type: 'number',
  default: 0
};

var unit_config = {
  type: 'set',
  values: ['px', '%'],
  default: 'px'
};

var size_config = new ConfigMask({
  type: 'object',
  properties: {
    value: value_config,
    unit: unit_config
  }
});

// use default values when input is missing
size_config.sanitize(); // {value: 0, unit: 'px'}

// add missing properties
size_config.sanitize({value: 100}); // {value: 100, unit: 'px'}

// ignore unknown properties
size_config.sanitize({xxx: 'yyy'}); // {value: 0, unit: 'px'}

Keep properties

By default, all undefined properties will be removed:
var my_config = {
  type: 'object',
  properties: {
    aaa: 'text'
  }
}

// property `ccc` will be removed
my_config.sanitize({aaa: 'bbb', ccc: 'ddd'}); // {aaa: 'bbb'}

If you want to keep undefined properties intact, add keep_property to config with truthy value:
var my_config = {
  type: 'object',
  properties: {
    aaa: 'text'
  },
  keep_properties: true
}

// property `ccc` will remain unchanged
my_config.sanitize({aaa: 'bbb', ccc: 'ddd'}); // {aaa: 'bbb', ccc: 'ddd'}

Nesting

You can nest ConfigMask objects together, creating very complex and interconnected types.
// Both of these objects work as standalone config mask...

var value_config = new ConfigMask({
  type: 'number',
  default: 0
});

var unit_config = new ConfigMask({
  type: 'set',
  values: ['px', '%'],
  default: 'px'
});

// ... but they are also used in this config mask to create more complex type.

var size_config = new ConfigMask({
  type: 'object',
  properties: {
    value: value_config,
    unit: unit_config
  }
});

Combined configs

If you need to accept various input types in configs, you can use "combined" type. It will sanitize input value through all the submasks and use first non-null result.
var navigation_config = {
  type: 'set',
  values: ['previous', 'next'],
  default: null
};

var index_config = {
  type: 'number',
  default: 0
}

var combined_config = new ConfigMask({
  type: 'combined',
  submasks: [navigation_config, index_config]
});

combined_config.sanitize('previous'); // 'previous'
combined_config.sanitize(123);        // 123
combined_config.sanitize('xxx');      // 0

Cloning to make variations

Sometimes you want to create a variation of existing ConfigMask. For example, you want the same config, but different default value. The easy way to do this is to use clone() method.
var person_age = new ConfigMask({
  type: 'number',
  default: 0
});
var old_person_age = person_age.clone({default: 60});

person_age.sanitize('xxx');     // 0
old_person_age.sanitize('xxx'); // 60

Documentation

Configuration

ConfigMask's configuration object.
Properties
  • type \(string \| Object) Identifier of item type (e.g. "number", "array") or custom config for Coerce object ().
  • default \any Default value to be used when input is invalid or missing.
  • values \Array If type is "set", this is the list of valid values.
  • properties \Object If type is "object", this is the list of its properties. The values should be Configuration objects.
  • keep_properties \boolean If type is "object" and "properties" are defined, unspecified properties of the object will not be removed.
  • submasks \Array<(Configuration \| ConfigMask)> List of sub-masks to be used when type is set to "combined". Sub-masks are evaluated in given order. First one that returns non-null value is used.
  • submask \(Configuration \| ConfigMask) Mask to be used when type is set to list_of. This property has priority over subtype
  • subtype \(string \| Object) Type of value allowed to be used when type is set to list_of.
  • parse \Function If set, it will be used to transform input before it is being sanitized.
  • validate \Function When sanitizing, passes parsed input through validator. If it does not pass, default value is used instead.
  • validate_after \Function Same as validate, but applied after the sanitation is done. This is useful for complex object types, where end result of sanitation may depend on result of sanitation of some of the properties.
  • on_invalid \Function Called when input is evaluated as invalid when sanitizing.
  • filter \Function If set, it will be used by list_of type to filter out values from result.

ConfigMask

Class representing ConfigMask.

constructor

Create ConfigMask.
Parameters

setOptions

Sets object's options.
Parameters

updateOptions

Adds new properties and replaces existing properties in object's options.
Parameters

sanitize

Applies config mask to input and returns sanitized value.
Parameters
  • input \any
  • param \any Parameter that will be added to all subsequent calls of sanitize(), parse() and validate().

Returns any

parse

Apply parse function on input, return unchanged input if not set.
Parameters
  • input
    param any Will be passed as second parameter to the parse function.

Examples
Add prefix to all texts.
var prefixed_text = new ConfigMask({
  type: 'text',
  parse: function (input) {return 'bbb' + input;}
});
prefixed_text.sanitize('aaa'); // 'aaabbb'

Returns any

validate

Validates input. Used to check parsed input before being used in sanitation.
Parameters
  • input
    param any Will be passed as second parameter to the validate function.
  • validation_function \Function Function to be used to validate input.

Examples
Limit maximum length of input.
var max_three_characters = new ConfigMask({
  type: 'text',
  validate: function (input) {return input.length <= 3;}
});
max_three_characters.sanitize('aaa'); // 'aaa'
max_three_characters.sanitize('aaabbb'); // ''

Returns boolean

clone

Creates exact copy of original object, updates the options with new ones.
Parameters

Returns
ConfigMask

ensureArray

Makes sure that input is an array. If input is undefined, an empty array is returned.
Parameters
  • input any

Returns
Array

applyFilter

If filter function is defined, applies it to data. Otherwise returns data unchanged.
Parameters
  • data Array
  • filter_function
Function
Returns Array

Bug reports, feature requests and contact

If you found any bugs, if you have feature requests or any questions, please, either file an issue at GitHub
or send me an e-mail at riki@fczbkk.com.

License

Config Mask is published under the MIT license.