npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

utilitario

v0.1.18

Published

Bulletproof identification (is), validation (constraints) and casting (cast)

Downloads

3

Readme

utilitario Build Status

NPM

Introduction

Bulletproof type identification (is), validation (constraints), casting (cast), parse (parse) and sanitize/transformation (transform) and truncate (truncate) for Javascript types.

Why? Because You shouldn't trust users/developers input. Users are evil and developers are even worst (they wont read the docs jump to your outdated examples and issue you)

Utilitario objectives

  • Support any input anywhere: RegExp(s), Object(s), Array(s), Number(s), String(s), Date(s), Infinite, NaN, Function(s) even Native function(s), anything and it will not crash!
  • Identify every Javascript primitive strictly and lossy.
  • Validate any input, giving multiple-meaningful errors, not just true/false. Something to debug properly.
  • Cast anything into something, and obvious but null means "cannot be casted".
  • Optional exceptions for user input.
  • Exceptions for developer input: required callbacks, invalid schema objects, etc.

Overview


var utilitario = require("utilitario");

// configure if needed

// allow NaN to be returned while casting ?
utilitario.options.allow_nan = false;

// treat numbers as valid dates
utilitario.options.timestamps_as_date = true;

// throw or return null ?
utilitario.options.throw_invalid_casts = false;

// cast.array should treat string as a possible array?
// fill the split character if you think so...
utilitario.options.cast_string_to_array_split = false;

// be extra caution with this, zero could be invalid in your app an also NaN
utilitario.options.cast_nan_to_zero = true;


// collection of functions
utilitario.is =          { /* Functions to identify input */},
utilitario.parse =       { /* parse your input from a given representation like json-string */ },
utilitario.transform =   { /* transform/sanitize your inputs*/ },
utilitario.constraints = { /* validations */ },
utilitario.truncate = { /* truncate input */ },
utilitario.cast =        { /* casts */ },

// 3 utils to conquer the world!
utilitario.validate();
utilitario.schema();
utilitario.sanitize();

is

  • dateStrict (Mixed val)

  • numberStrict (Mixed val)

  • decimal (Mixed val)

  • integer (Mixed val)

  • nan (Mixed val)

  • nullStrict (Mixed val)

  • null (Mixed val)

  • notNull (Mixed val)

  • empty (Mixed val)

  • infinite (Mixed val)

  • notEmpty (Mixed val)

  • regex (Mixed val)

  • object (Mixed val)

  • string (Mixed val)

  • html (Mixed val)

  • array (Mixed val)

  • date (Mixed val)

  • json (Mixed val)

    Check for Object/Array begin/end string. Made for fast test, should be enough for most of the uses, considered that you will need to use JSON.parse eventually

  • jsonStrict (val)

    use JSON.parse... it's slow. Consider use is.json

  • boolean (Mixed val)

cast

Force input to be valid is ok. Force to be valid and a type is even better.

When casting null is synonym of "cannot be casted"

  • integer (val)
  • float (val)
  • string (val)
  • date (val)
  • regex (value)
  • object (val)
  • array (val)
  • boolean (val)
  • binary (bin)

If you want exceptions on invalid castings setup utilitario with:

  • throw_invalid_casts = true
  • allow_nan = true

constraints

  • keys (value, keys)
  • in (needle, haystack)
  • notIn (needle, haystack)
  • contains (needle, haystack)
  • notContains (needle, haystack)
  • equals (a, b)
  • notEquals (a, b)
  • equalsStrict (a, b)
  • notEqualsStrict (a, b)
  • regex (str, pattern, modifiers)
  • notRegex (str, pattern, modifiers)
  • tillToday (str, date)
  • fromToday (str, date)
  • pastDate (str, date)
  • futureDate (str, date)
  • dateAfter (str, date)
  • dateBefore (str, date)
  • email (str)
  • url (str)
  • alpha (val)
  • alphanumeric (val)
  • numeric (val)
  • hexadecimal (str)
  • hexColor (str)
  • length (val, min, max)
  • UUIDv3 (val)
  • UUIDv4 (val)
  • UUIDv5 (val)
  • min (val, min)
  • max (val, max)
  • ip (str)
  • ip4 (str)
  • ip6 (str)
  • buffer (val)

truncate

  • maxLength (val, max)
  • min (val, min)
  • max (val, max)
  • dateAfter (str, date)
  • dateBefore (str, date)
  • alphanumeric: (str, replacement)
  • alpha: (str, replacement)
  • hexadecimal: (str, replacement)

parse

Parse given

  • string (val)

    Try to transform a string into the perfect javascript representation.

    Did you notice the evilness? useful but risky.

    • "undefined" -> undefined
    • "null" -> null
    • "true" -> true
    • "false" -> false
    • "NaN" -> NaN
    • "Infinity" -> Infinity
    • is.decimal -> cast.number
  • querystring (val)

  • json (val)

  • url (urlStr, parseQueryString, slashesDenoteHost)

transform

Transform given value into destination representation.

  • querystring (val)

    use qs module

  • json (val)

    alias of JSON.stringify

  • length (val, max)

  • lowercase (val)

  • uppercase (val)

  • escapeHTML (val)

  • stripTags (input, allowed)

  • hexToBin (val)

  • toCamelCase (val)

  • camelToDash (val)

  • toUnderscore (val)

  • trim (val)

  • removeDiacritics (val)

schema

Check anything against given schema to have fully input validation/sanitize/transform/cast solution.


require("utilitario").schema(mixed, structure/*object*/, errors/*object by reference*/, options/*optional, object*/, __path/*internal*/);

// example
var errors = {},
    ret = utilitario.schema("100", {
        constraints: {
            "integer": ["integer constraint fail"],
        },
        cast: "integer"
    }, errors);

// tap test
t.deepEqual(ret, 100, "is 100 number");
t.deepEqual(errors, {}, "no errors");

Structure object

Schema Leaf (anything not array/object)

var schema = {
    // array of object
    constraints: [{
        // key: array|true
        // There are two ways to define error message, use messages or add the string as last argument.
        // messages has higher priority, at least one of those methods must define the error.
        // messages is preferred.
        constraint_function_name: [arguments, "error-optional"],

        // example
        length: [5, 20]

        // as many as you want...
    }],

    // messages list, must have the same structure as constrains.
    messages: {
        "length": "string is too long or too short"
    },

    sanitize: [{
        transform_function_name: [arguments],

        // example
        lowercase: null // null is permitted as input, meaning no arguments
        stripTags: ["<strong><b><i><em>"]
    }],

    // default value, if any constraints fail, or optional=true
    default: "anytype", // mixed

    // cast is always called, even if you use a default value.
    cast: "string",

    // empty by default
    // base path for error reporting
    base_path: ""
}

There is two additions to constraints: nullable and optional. Both are considered as final constrains once they are true, nothing more is tested.

Schema Trunk (array/object, recursive)

Arrays

{
    cast: "array", // mandatory
    items: "Schema Leaf/Trunk object" // schema that all elements must fulfill
}

// example array of integers
var array_schema = {
    cast: "array", // mandatory
    items: {
        constraints: {
            "integer": true,
        },
        messages: {
            integer: "some elements in the array are not integers"
        },
        cast: "integer"
    }, // schema that all elements must fulfill
    base_path: "list"
}

// tap test
var errors = {};
t.deepEqual(utilitario.schema([1,2,"3"], array_schema, errors), [1,2,3], "ok!");
t.deepEqual(errors, {}, "no errors");

errors = {};
t.deepEqual(utilitario.schema(["abc"], array_schema, errors), [0], "");
t.deepEqual(errors, {"list.0": [["some elements in the array are not integers"], true]}, "with errors");

Objects

{
    cast: "object", // mandatory
    object: {
        key: "Schema Leaf/Trunk object" // schema that given key must fulfill
    }
}

// example
var object_schema = {
    cast: "object", // mandatory
    object: {
        int: {
            constraints: {
                "integer": ["int key is not a valid integer"],
            },
            cast: "integer"
        },
        string: {
            constraints: {
                "string": ["string key is not a valid string"],
            },
            cast: "string"
        }
    }
}

// tap test
var errors = {};
t.deepEqual(utilitario.schema({int: 10, string: "abc"}, object_schema, errors), {int: 10, string: "abc"}, "ok!");

errors = {};
t.deepEqual(utilitario.schema({string: "abc"}, object_schema, errors), {int: undefined, string: "abc"}, "ok!");
t.deepEqual(errors, {int: [["is undefined"]]}, "notice that int was undefined");

errors object

The combo messages (in the schema) and errors returned by schema validation can be used to write meaningful messages like in this example:


var sprintf_js = require("sprintf-js"),
    i,
    errors = [],
    raw_errors = {},
    path;

// message:
// 'Minimum of %(arguments[0])s characters',

// validate
// utilitario.schema('', '', raw_errors)

for (path in raw_errors) {
    for (i = 0; i < raw_errors[path].length; ++i) {
        message = raw_errors[path][i].shift();
        console.log(sprintf_js.sprintf(message, {
            arguments: raw_errors[path][i]
            // you can add more info here, path/stack/user
        }));
    }
}

options

  • filter callback(String path, Mixed value): Boolean

Filter is used to ignore some data, that you want to ignore validation. If you return false, the returned value be the given, and no cast will be performed. Just ignored and continue.

  • create_properties Boolean

Create object properties if they are not defined, set the value to default or undefined. Note: This could lead to some validation errors: default: null -- constraints: {nullable: false}

This can create an empty/default object structure from an empty object.

Dependencies

node-querystring

is-html

lodash.clonedeep

Developement

tap (tests)

Performance

  • typeof is called many times, but it should be fast enough.
  • has many internal calls to avoid code duplication, in the future those call could be inlined see funlinify

Install

With npm do:


npm install utilitario

test (travis-ci ready!)


npm test
// or
cd /test
node test-class.js

REPL

{ options:
   { allow_nan: false,
     timestamps_as_date: true,
     throw_invalid_casts: false,
     cast_string_to_array_split: false,
     cast_nan_to_zero: true },
  is:
   { dateStrict: [Function],
     numberStrict: [Function],
     decimal: [Function],
     integer: [Function],
     nan: [Function],
     nullStrict: [Function],
     null: [Function],
     notNull: [Function],
     empty: [Function],
     infinite: [Function],
     notEmpty: [Function],
     regex: [Function],
     object: [Function],
     string: [Function],
     html: [Function],
     array: [Function],
     date: [Function],
     json: [Function],
     jsonStrict: [Function],
     boolean: [Function] },
  parse:
   { string: [Function],
     querystring: [Function],
     json: [Function],
     url: [Function] },
  transform:
   { querystring: [Function],
     json: [Function],
     length: [Function],
     lowercase: [Function],
     uppercase: [Function],
     escapeHTML: [Function],
     stripTags: [Function],
     hexToBin: [Function],
     toCamelCase: [Function],
     camelToDash: [Function],
     toUnderscore: [Function],
     trim: [Function],
     removeDiacritics: [Function] },
  constraints:
   { keys: [Function],
     in: [Function],
     notIn: [Function],
     contains: [Function],
     notContains: [Function],
     equals: [Function],
     notEquals: [Function],
     equalsStrict: [Function],
     notEqualsStrict: [Function],
     regex: [Function],
     notRegex: [Function],
     tillToday: [Function],
     fromToday: [Function],
     pastDate: [Function],
     futureDate: [Function],
     dateAfter: [Function],
     dateBefore: [Function],
     email: [Function],
     url: [Function],
     alpha: [Function],
     alphanumeric: [Function],
     numeric: [Function],
     hexadecimal: [Function],
     hexColor: [Function],
     minLength: [Function],
     maxLength: [Function],
     length: [Function],
     UUIDv3: [Function],
     UUIDv4: [Function],
     UUIDv5: [Function],
     min: [Function],
     max: [Function],
     ip: [Function],
     ip4: [Function],
     ip6: [Function],
     buffer: [Function],
     containUppercase: [Function],
     containLowercase: [Function],
     constainNumber: [Function],
     constainLetter: [Function],
     noSpaces: [Function],
     maxDecimals: [Function] },
  truncate:
   { maxLength: [Function],
     min: [Function],
     max: [Function],
     dateAfter: [Function],
     dateBefore: [Function],
     alphanumeric: [Function],
     alpha: [Function],
     hexadecimal: [Function] },
  cast:
   { integer: [Function],
     float: [Function],
     string: [Function],
     date: [Function],
     regex: [Function],
     object: [Function],
     array: [Function],
     boolean: [Function],
     binary: [Function],
     number: [Function] },
  validate: [Function: __validate],
  schema: [Function: __schema],
  sanitize: [Function: __sanitize] }

license

MIT.