├── .eslintignore ├── test ├── eslint.js ├── predicates │ ├── existy.js │ ├── null.js │ ├── undefined.js │ ├── boolean.js │ ├── array.js │ ├── buffer.js │ ├── date.js │ ├── function.js │ ├── hexColor.js │ ├── number.js │ ├── finite.js │ ├── integer.js │ ├── stream.js │ ├── plainObject.js │ ├── natural.js │ ├── string.js │ ├── email.js │ ├── uri.js │ ├── url.js │ └── webUrl.js └── index.js ├── .babelrc ├── predicates ├── null.js ├── array.js ├── buffer.js ├── undefined.js ├── integer.js ├── number.js ├── boolean.js ├── finite.js ├── function.js ├── existy.js ├── stream.js ├── date.js ├── hexColor.js ├── natural.js ├── plainObject.js ├── string.js ├── uri.js ├── email.js ├── url.js └── webUrl.js ├── jsconfig.json ├── .eslintrc ├── .gitignore ├── package.json ├── index.js ├── README.md └── lib └── rfc3986.js /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules -------------------------------------------------------------------------------- /test/eslint.js: -------------------------------------------------------------------------------- 1 | require('mocha-eslint')(['./src', './test']); 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "es2015", "react", "stage-2" ] 3 | } 4 | -------------------------------------------------------------------------------- /predicates/null.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is null 5 | * 6 | * @param {*} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return value === null; 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /predicates/array.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is an array 5 | * 6 | * @param {Array<*>} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return Array.isArray(value); 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /predicates/buffer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is a buffer 5 | * 6 | * @param {Buffer} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return Buffer.isBuffer(value); 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /predicates/undefined.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is undefined 5 | * 6 | * @param {*} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return value === undefined; 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /predicates/integer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is an integer 5 | * 6 | * @param {Number} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return Number.isInteger(value); 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /predicates/number.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is a number 5 | * 6 | * @param {Number} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return typeof value === 'number'; 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /predicates/boolean.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is a boolean 5 | * 6 | * @param {Boolean} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return typeof value === 'boolean'; 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /predicates/finite.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is a finite number 5 | * 6 | * @param {Number} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return Number.isFinite(value); 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /predicates/function.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is a function 5 | * 6 | * @param {Function} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return typeof value === 'function'; 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /predicates/existy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is null or undefined 5 | * 6 | * @param {*} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | return value !== null && value !== undefined; 11 | } 12 | 13 | module.exports = validate; 14 | -------------------------------------------------------------------------------- /test/predicates/existy.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: true }, 5 | { value: 1, result: true }, 6 | { value: [], result: true }, 7 | { value: '', result: true }, 8 | { value: 'abc', result: true }, 9 | ]; 10 | -------------------------------------------------------------------------------- /test/predicates/null.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: true }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: 1, result: false }, 6 | { value: [], result: false }, 7 | { value: '', result: false }, 8 | { value: 'abc', result: false }, 9 | ]; 10 | -------------------------------------------------------------------------------- /test/predicates/undefined.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: true }, 4 | { value: () => {}, result: false }, 5 | { value: 1, result: false }, 6 | { value: [], result: false }, 7 | { value: '', result: false }, 8 | { value: 'abc', result: false }, 9 | ]; 10 | -------------------------------------------------------------------------------- /test/predicates/boolean.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: 123, result: false }, 4 | { value: 'abc', result: false }, 5 | { value: 0, result: false }, 6 | { value: '', result: false }, 7 | { value: {}, result: false }, 8 | { value: true, result: true }, 9 | { value: false, result: true }, 10 | ]; 11 | -------------------------------------------------------------------------------- /test/predicates/array.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: 1, result: false }, 7 | { value: [], result: true }, 8 | { value: [123, 456], result: true }, 9 | { value: ['a', 123, null], result: true }, 10 | ]; 11 | -------------------------------------------------------------------------------- /predicates/stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const stream = require('stream'); 4 | 5 | /** 6 | * Checks if value is a stream 7 | * Based on: https://github.com/rvagg/isstream 8 | * 9 | * @param {Stream} value - Value 10 | * @returns {Boolean} 11 | */ 12 | function validate(value) { 13 | return value instanceof stream.Stream; 14 | } 15 | 16 | module.exports = validate; 17 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=759670 3 | // for the documentation about the jsconfig.json format 4 | "compilerOptions": { 5 | "target": "es6", 6 | "module": "commonjs", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "exclude": [ 10 | "node_modules", 11 | "bower_components", 12 | "jspm_packages", 13 | "tmp", 14 | "temp" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /test/predicates/buffer.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: 1, result: false }, 7 | { value: [], result: false }, 8 | { value: [123, 456], result: false }, 9 | { value: ['a', 123, null], result: false }, 10 | { value: Buffer.from('string'), result: true }, 11 | ]; 12 | -------------------------------------------------------------------------------- /test/predicates/date.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: 123, result: false }, 4 | { value: 'abc', result: false }, 5 | { value: 0, result: false }, 6 | { value: '', result: false }, 7 | { value: {}, result: false }, 8 | { value: true, result: false }, 9 | { value: false, result: false }, 10 | { value: new Date(), result: true }, 11 | { value: (2 ** 2) - 1, result: false }, 12 | ]; 13 | -------------------------------------------------------------------------------- /test/predicates/function.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: 123, result: false }, 4 | { value: 'abc', result: false }, 5 | { value: 0, result: false }, 6 | { value: '', result: false }, 7 | { value: {}, result: false }, 8 | { value: true, result: false }, 9 | { value: false, result: false }, 10 | { value: () => {}, result: true }, 11 | { value: function test() {}, result: true }, 12 | ]; 13 | -------------------------------------------------------------------------------- /predicates/date.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is a date object 5 | * 6 | * @param {Date} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value) { 10 | // Basic check for Type object that's not null 11 | if (typeof value === 'object' && value !== null) { 12 | return Object.getPrototypeOf(value) === Date.prototype; 13 | } 14 | 15 | return false; 16 | } 17 | 18 | module.exports = validate; 19 | -------------------------------------------------------------------------------- /test/predicates/hexColor.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: 1, result: false }, 7 | { value: 'FF3333', result: false }, 8 | { value: '#FF33', result: false }, 9 | { value: '#FF33333', result: false }, 10 | { value: '#FF3333', result: true }, 11 | { value: '#FFF', result: true }, 12 | ]; 13 | -------------------------------------------------------------------------------- /predicates/hexColor.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const isString = require('./string'); 4 | 5 | const re = /^#([0-9A-F]{3}|[0-9A-F]{6})$/i; 6 | 7 | /** 8 | * Checks if value is a hex color like #FFAA99 9 | * 10 | * @param {String} hexColor 11 | * @returns {Boolean} 12 | */ 13 | function validate(hexColor) { 14 | if (!isString(hexColor)) { 15 | return false; 16 | } 17 | 18 | return hexColor.match(re) !== null; 19 | } 20 | 21 | module.exports = validate; 22 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 8, 4 | "sourceType": "module", 5 | "ecmaFeatures": { 6 | "jsx": true, 7 | "modules": true 8 | } 9 | }, 10 | "env": { 11 | "es6": true, 12 | "browser": true, 13 | "node": true, 14 | "mocha": true 15 | }, 16 | "rules": { 17 | "strict": [0, "global"], 18 | "padded-blocks": [2, "never"], 19 | "arrow-body-style": [0, "as-needed"], 20 | "no-use-before-define": [2, "nofunc"] 21 | } 22 | } -------------------------------------------------------------------------------- /predicates/natural.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is a natural number (non-negative integer) 5 | * 6 | * @param {Number} value - Value 7 | * @returns {Boolean} 8 | */ 9 | function validate(value, options) { 10 | const disallowZero = options && options.disallowZero; 11 | return Number.isInteger(value) && isPositive(value, disallowZero); 12 | } 13 | 14 | function isPositive(value, disallowZero) { 15 | if (disallowZero) { 16 | return value > 0; 17 | } 18 | 19 | return value >= 0; 20 | } 21 | 22 | module.exports = validate; 23 | -------------------------------------------------------------------------------- /test/predicates/number.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: '1', result: false }, 7 | { value: 1, result: true }, 8 | { value: 1.1, result: true }, 9 | { value: -1, result: true }, 10 | { value: -1.1, result: true }, 11 | { value: Math.PI, result: true }, 12 | { value: NaN, result: true }, 13 | { value: Infinity, result: true }, 14 | { value: -Infinity, result: true }, 15 | { value: 2e64, result: true }, 16 | { value: (2 ** 2) - 1, result: true }, 17 | ]; 18 | -------------------------------------------------------------------------------- /test/predicates/finite.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: '1', result: false }, 7 | { value: 1, result: true }, 8 | { value: 1.1, result: true }, 9 | { value: -1, result: true }, 10 | { value: -1.1, result: true }, 11 | { value: Math.PI, result: true }, 12 | { value: NaN, result: false }, 13 | { value: Infinity, result: false }, 14 | { value: -Infinity, result: false }, 15 | { value: 2e64, result: true }, 16 | { value: (2 ** 2) - 1, result: true }, 17 | ]; 18 | -------------------------------------------------------------------------------- /predicates/plainObject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is a plain object 5 | * Based on: http://stackoverflow.com/questions/5876332/how-can-i-differentiate-between-an-object-literal-other-javascript-objects 6 | * 7 | * @param {Object} value - Value 8 | * @returns {Boolean} 9 | */ 10 | function validate(value) { 11 | // Basic check for Type object that's not null 12 | if (typeof value === 'object' && value !== null) { 13 | const proto = Object.getPrototypeOf(value); 14 | return proto === Object.prototype || proto === null; 15 | } 16 | 17 | return false; 18 | } 19 | 20 | module.exports = validate; 21 | -------------------------------------------------------------------------------- /test/predicates/integer.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: '1', result: false }, 7 | { value: 1, result: true }, 8 | { value: 1.1, result: false }, 9 | { value: -1, result: true }, 10 | { value: -1.1, result: false }, 11 | { value: Math.PI, result: false }, 12 | { value: NaN, result: false }, 13 | { value: Infinity, result: false }, 14 | { value: -Infinity, result: false }, 15 | { value: 2e64, result: true }, 16 | { value: (2 ** 2) - 1, result: true }, 17 | ]; 18 | -------------------------------------------------------------------------------- /test/predicates/stream.js: -------------------------------------------------------------------------------- 1 | const Stream = require('stream'); 2 | 3 | module.exports = [ 4 | { value: null, result: false }, 5 | { value: undefined, result: false }, 6 | { value: () => {}, result: false }, 7 | { value: 1, result: false }, 8 | { value: [], result: false }, 9 | { value: '', result: false }, 10 | { value: 'abc', result: false }, 11 | { value: {}, result: false }, 12 | { value: new Stream.Readable(), result: true }, 13 | { value: new Stream.Writable(), result: true }, 14 | { value: new Stream.Duplex(), result: true }, 15 | { value: new Stream.Transform(), result: true }, 16 | { value: new Stream.PassThrough(), result: true }, 17 | ]; 18 | -------------------------------------------------------------------------------- /test/predicates/plainObject.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: 123, result: false }, 4 | { value: 'abc', result: false }, 5 | { value: 0, result: false }, 6 | { value: '', result: false }, 7 | { value: {}, result: true }, 8 | { value: { constructor: 'String' }, result: true }, 9 | { value: new Object({}), result: true }, // eslint-disable-line 10 | { value: new Object(null), result: true }, // eslint-disable-line 11 | { value: Object.assign({}), result: true }, 12 | { value: true, result: false }, 13 | { value: false, result: false }, 14 | { value: () => {}, result: false }, 15 | { value: function test() {}, result: false }, 16 | ]; 17 | -------------------------------------------------------------------------------- /predicates/string.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Checks if value is an array 5 | * 6 | * @param {String} value - Value 7 | * @param {object} [options] - Options 8 | * @returns {Boolean} 9 | */ 10 | function validate(value, options) { 11 | let isString = value instanceof String || typeof value === 'string'; 12 | 13 | if (!options) { 14 | return isString; 15 | } 16 | 17 | // Optional checks 18 | if (options.endsWith && !value.endsWith(options.endsWith)) { 19 | isString = false; 20 | } 21 | 22 | if (options.startsWith && !value.startsWith(options.startsWith)) { 23 | isString = false; 24 | } 25 | 26 | return isString; 27 | } 28 | 29 | module.exports = validate; 30 | -------------------------------------------------------------------------------- /test/predicates/natural.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: '1', result: false }, 7 | { value: 0, result: true }, 8 | { value: 0, options: { disallowZero: true }, result: false }, 9 | { value: 1, result: true }, 10 | { value: 1.1, result: false }, 11 | { value: -1, result: false }, 12 | { value: -1.1, result: false }, 13 | { value: Math.PI, result: false }, 14 | { value: NaN, result: false }, 15 | { value: Infinity, result: false }, 16 | { value: -Infinity, result: false }, 17 | { value: 2e64, result: true }, 18 | { value: (2 ** 2) - 1, result: true }, 19 | ]; 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directory 29 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 30 | node_modules 31 | 32 | .DS_Store 33 | .idea -------------------------------------------------------------------------------- /predicates/uri.js: -------------------------------------------------------------------------------- 1 | const re = require('../lib/rfc3986'); 2 | const isString = require('./string'); 3 | 4 | /** 5 | * Checks if string is a valid uri 6 | * @param {String} value - Value 7 | * @param {object} [options] - Additional options 8 | * @returns {Boolean} 9 | */ 10 | 11 | function validate(value, options) { 12 | if (!isString(value)) { 13 | return false; 14 | } 15 | 16 | let isUri = value.match(re) !== null; 17 | 18 | if (!options) { 19 | return isUri; 20 | } 21 | 22 | // Optional checks 23 | if (options.endsWith && !value.endsWith(options.endsWith)) { 24 | isUri = false; 25 | } 26 | 27 | if (options.startsWith && !value.startsWith(options.startsWith)) { 28 | isUri = false; 29 | } 30 | 31 | return isUri; 32 | } 33 | 34 | module.exports = validate; 35 | -------------------------------------------------------------------------------- /test/predicates/string.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: 1, result: false }, 6 | { value: [], result: false }, 7 | { value: '', result: true }, 8 | { value: 'abc', result: true }, 9 | { value: 'abc', options: { startsWith: 'a' }, result: true }, 10 | { value: 'abc', options: { startsWith: 'b' }, result: false }, 11 | { value: 'abc', options: { endsWith: 'c' }, result: true }, 12 | { value: 'abc', options: { endsWith: 'd' }, result: false }, 13 | { value: 'abc', options: { startsWith: 'b', endsWith: 'c' }, result: false }, 14 | { value: 'abc', options: { startsWith: 'a', endsWith: 'd' }, result: false }, 15 | { value: 'abc', options: { startsWith: 'a', endsWith: 'c' }, result: true }, 16 | ]; 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "valido", 3 | "version": "2.1.0", 4 | "description": "Check and validation library", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha", 8 | "prepublish": "npm test" 9 | }, 10 | "engines": { 11 | "node": ">=6.5.0" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/moooji/valido.git" 16 | }, 17 | "keywords": [ 18 | "validation", 19 | "check", 20 | "validate", 21 | "predicate" 22 | ], 23 | "author": "Steffen Strätz", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/moooji/valido/issues" 27 | }, 28 | "devDependencies": { 29 | "chai": "^4.2.0", 30 | "eslint": "^5.16.0", 31 | "lodash": "^4.17.11", 32 | "mocha": "^6.1.4", 33 | "mocha-eslint": "^5.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/predicates/email.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: 1, result: false }, 7 | { value: 'abc', result: false }, 8 | { value: {}, result: false }, 9 | { value: [], result: false }, 10 | { value: 'google.com', result: false }, 11 | { value: 'http://localhost:3200/website.html', result: false }, 12 | { value: 'bob@test.com', result: true }, 13 | { value: 'bob.parker@www.test.com', result: true }, 14 | { value: 'bob@test.com', options: { startsWith: 'bob' }, result: true }, 15 | { value: 'bob@test.com', options: { startsWith: 'peter' }, result: false }, 16 | { value: 'bob@test.com', options: { endsWith: 'test.com' }, result: true }, 17 | { value: 'bob@test.com', options: { endsWith: 'bob.com' }, result: false }, 18 | ]; 19 | -------------------------------------------------------------------------------- /predicates/email.js: -------------------------------------------------------------------------------- 1 | const isString = require('./string'); 2 | 3 | // https://www.w3.org/TR/html5/forms.html#valid-e-mail-address 4 | const re = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; // eslint-disable-line max-len 5 | 6 | /** 7 | * Checks if string is a valid email 8 | * @param {String} value - Value 9 | * @param {object} [options] - Additional options 10 | * @returns {Boolean} 11 | */ 12 | 13 | function validate(value, options) { 14 | if (!isString(value)) { 15 | return false; 16 | } 17 | 18 | let isEmail = value.match(re) !== null; 19 | 20 | if (!options) { 21 | return isEmail; 22 | } 23 | 24 | // Optional checks 25 | if (options.endsWith && !value.endsWith(options.endsWith)) { 26 | isEmail = false; 27 | } 28 | 29 | if (options.startsWith && !value.startsWith(options.startsWith)) { 30 | isEmail = false; 31 | } 32 | 33 | return isEmail; 34 | } 35 | 36 | module.exports = validate; 37 | -------------------------------------------------------------------------------- /test/predicates/uri.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: 1, result: false }, 7 | { value: 'abc', result: false }, 8 | { value: {}, result: false }, 9 | { value: [], result: false }, 10 | { value: 'google.com', result: false }, 11 | { value: 'http://localhost:3200/website.html', result: true }, 12 | { value: 'https://127.0.0.1:3128', result: true }, 13 | { value: 'http://www.google.com', result: true }, 14 | { value: 'https://www.google.com', result: true }, 15 | { value: 'https://8.8.8.8:3128', result: true }, 16 | { value: 'mongodb://www.google.com', result: true }, 17 | { value: '/index.html', result: false }, 18 | { value: 'http://google.com', result: true }, 19 | { value: 'https://pass:bob@www.google.com:8080/index.html?param=2&yy=abc', result: true }, 20 | { value: 'https://www.google.com', options: { endsWith: '/' }, result: false }, 21 | { value: 'https://www.google.com/', options: { endsWith: '/' }, result: true }, 22 | { value: 'https://www.google.com', options: { startsWith: 'https://www.ebay' }, result: false }, 23 | { value: 'https://www.google.com/', options: { startsWith: 'https://www.google' }, result: true }, 24 | { value: 'https://www.google.com/', options: { startsWith: 'https://www.google', endsWith: '/' }, result: true }, 25 | { value: 'https://www.google.com', options: { startsWith: 'https://www.google', endsWith: '/' }, result: false }, 26 | { value: 'https://www.google.com/', options: { startsWith: 'https://www.ebay', endsWith: '/' }, result: false }, 27 | ]; 28 | -------------------------------------------------------------------------------- /test/predicates/url.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: 1, result: false }, 7 | { value: 'abc', result: false }, 8 | { value: {}, result: false }, 9 | { value: [], result: false }, 10 | { value: 'http://', result: false }, 11 | { value: '/index.html', result: false }, 12 | { value: 'google.com', result: false }, 13 | { value: 'https://127.0.0.1:3128', result: true }, 14 | { value: 'https://8.8.8.8.8:3128', result: false }, 15 | { value: 'mongodb://www.google.com', result: false }, 16 | { value: 'http://www.google.com', result: true }, 17 | { value: 'http://google.com', result: true }, 18 | { value: 'https://www.google.com', result: true }, 19 | { value: 'https://8.8.8.8:3128', result: true }, 20 | { value: 'https://pass:bob@www.google.com:8080/index.html?param=2&yy=abc', result: true }, 21 | { value: 'https://www.google.com', options: { endsWith: '/' }, result: false }, 22 | { value: 'https://www.google.com/', options: { endsWith: '/' }, result: true }, 23 | { value: 'https://www.google.com', options: { startsWith: 'https://www.ebay' }, result: false }, 24 | { value: 'https://www.google.com/', options: { startsWith: 'https://www.google' }, result: true }, 25 | { value: 'https://www.google.com/', options: { startsWith: 'https://www.google', endsWith: '/' }, result: true }, 26 | { value: 'https://www.google.com', options: { startsWith: 'https://www.google', endsWith: '/' }, result: false }, 27 | { value: 'https://www.google.com/', options: { startsWith: 'https://www.ebay', endsWith: '/' }, result: false }, 28 | ]; 29 | -------------------------------------------------------------------------------- /test/predicates/webUrl.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: null, result: false }, 3 | { value: undefined, result: false }, 4 | { value: () => {}, result: false }, 5 | { value: '', result: false }, 6 | { value: 1, result: false }, 7 | { value: 'abc', result: false }, 8 | { value: {}, result: false }, 9 | { value: [], result: false }, 10 | { value: 'http://', result: false }, 11 | { value: '/index.html', result: false }, 12 | { value: 'google.com', result: false }, 13 | { value: 'https://127.0.0.1:3128', result: false }, 14 | { value: 'https://8.8.8.8.8:3128', result: false }, 15 | { value: 'mongodb://www.google.com', result: false }, 16 | { value: 'http://www.google.com', result: true }, 17 | { value: 'http://google.com', result: true }, 18 | { value: 'https://www.google.com', result: true }, 19 | { value: 'https://8.8.8.8:3128', result: true }, 20 | { value: 'https://pass:bob@www.google.com:8080/index.html?param=2&yy=abc', result: true }, 21 | { value: 'https://www.google.com', options: { endsWith: '/' }, result: false }, 22 | { value: 'https://www.google.com/', options: { endsWith: '/' }, result: true }, 23 | { value: 'https://www.google.com', options: { startsWith: 'https://www.ebay' }, result: false }, 24 | { value: 'https://www.google.com/', options: { startsWith: 'https://www.google' }, result: true }, 25 | { value: 'https://www.google.com/', options: { startsWith: 'https://www.google', endsWith: '/' }, result: true }, 26 | { value: 'https://www.google.com', options: { startsWith: 'https://www.google', endsWith: '/' }, result: false }, 27 | { value: 'https://www.google.com/', options: { startsWith: 'https://www.ebay', endsWith: '/' }, result: false }, 28 | ]; 29 | -------------------------------------------------------------------------------- /predicates/url.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const isString = require("./string"); 4 | 5 | // Based on 6 | // https://gist.github.com/o5/6cb4b0178c5a509cad03 7 | 8 | const re = new RegExp( 9 | "^" + 10 | // protocol identifier 11 | "(?:(?:https?|ftp)://)" + 12 | // user:pass authentication 13 | "(?:\\S+(?::\\S*)?@)?" + 14 | "(?:" + 15 | // IP address dotted notation octets 16 | // excludes loopback network 0.0.0.0 17 | // excludes reserved space >= 224.0.0.0 18 | // excludes network & broacast addresses 19 | // (first & last IP address of each class) 20 | "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" + 21 | "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" + 22 | "(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" + 23 | "|" + 24 | // host name 25 | "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" + 26 | // domain name 27 | "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" + 28 | // TLD identifier 29 | "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" + 30 | // TLD may end with dot 31 | "\\.?" + 32 | ")" + 33 | // port number 34 | "(?::\\d{1,5})?" + 35 | // resource path 36 | "(?:[/?#]\\S*)?" + 37 | "$", 38 | "i" 39 | ); 40 | 41 | /** 42 | * Checks if string is a valid url 43 | * @param {String} value - Value 44 | * @param {object} [options] - Additional options 45 | * @returns {Boolean} 46 | */ 47 | 48 | function validate(value, options) { 49 | if (!isString(value)) { 50 | return false; 51 | } 52 | 53 | let isUrl = value.match(re) !== null; 54 | 55 | if (!options) { 56 | return isUrl; 57 | } 58 | 59 | // Optional checks 60 | if (options.endsWith && !value.endsWith(options.endsWith)) { 61 | isUrl = false; 62 | } 63 | 64 | if (options.startsWith && !value.startsWith(options.startsWith)) { 65 | isUrl = false; 66 | } 67 | 68 | return isUrl; 69 | } 70 | 71 | module.exports = validate; 72 | -------------------------------------------------------------------------------- /predicates/webUrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const isString = require('./string'); 4 | 5 | // Based on 6 | // https://gist.github.com/o5/6cb4b0178c5a509cad03 7 | 8 | const re = new RegExp( 9 | '^' + 10 | 11 | // protocol identifier 12 | '(?:(?:https?|ftp)://)' + 13 | 14 | // user:pass authentication 15 | '(?:\\S+(?::\\S*)?@)?' + 16 | '(?:' + 17 | 18 | // IP address exclusion 19 | // private & local networks 20 | '(?!(?:10|127)(?:\\.\\d{1,3}){3})' + 21 | '(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})' + 22 | '(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})' + 23 | 24 | // IP address dotted notation octets 25 | // excludes loopback network 0.0.0.0 26 | // excludes reserved space >= 224.0.0.0 27 | // excludes network & broacast addresses 28 | // (first & last IP address of each class) 29 | '(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])' + 30 | '(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}' + 31 | '(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))' + 32 | '|' + 33 | 34 | // host name 35 | '(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)' + 36 | 37 | // domain name 38 | '(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*' + 39 | 40 | // TLD identifier 41 | '(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))' + 42 | 43 | // TLD may end with dot 44 | '\\.?' + 45 | ')' + 46 | 47 | // port number 48 | '(?::\\d{1,5})?' + 49 | 50 | // resource path 51 | '(?:[/?#]\\S*)?' + 52 | '$', 'i' 53 | ); 54 | 55 | /** 56 | * Checks if string is a valid web url (no local or private networks) 57 | * @param {String} value - Value 58 | * @param {object} [options] - Additional options 59 | * @returns {Boolean} 60 | */ 61 | 62 | function validate(value, options) { 63 | if (!isString(value)) { 64 | return false; 65 | } 66 | 67 | let isWebUrl = value.match(re) !== null; 68 | 69 | if (!options) { 70 | return isWebUrl; 71 | } 72 | 73 | // Optional checks 74 | if (options.endsWith && !value.endsWith(options.endsWith)) { 75 | isWebUrl = false; 76 | } 77 | 78 | if (options.startsWith && !value.startsWith(options.startsWith)) { 79 | isWebUrl = false; 80 | } 81 | 82 | return isWebUrl; 83 | } 84 | 85 | module.exports = validate; 86 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const fs = require("fs"); 4 | const path = require("path"); 5 | const _ = require("lodash"); 6 | const chai = require("chai"); 7 | const valido = require("../index"); 8 | const expect = chai.expect; 9 | 10 | const predicateDir = path.join(__dirname, "../predicates"); 11 | const predicateTestsDir = path.join(__dirname, "./predicates"); 12 | const predicateFiles = fs.readdirSync(predicateDir); 13 | 14 | predicateFiles.forEach(file => { 15 | const testsPath = path.join(predicateTestsDir, file); 16 | const filePath = path.join(predicateDir, file); 17 | const fileInfo = path.parse(filePath); 18 | const predicateName = fileInfo.name; 19 | const tests = require(testsPath); // eslint-disable-line global-require 20 | 21 | const validValues = _.map(_.filter(tests, { result: true }), "value"); 22 | const invalidValues = _.map(_.filter(tests, { result: false }), "value"); 23 | 24 | const hasTestValue = test => !valido.existy(test.value); 25 | const optionalValueTests = _.filter(tests, hasTestValue); 26 | 27 | describe(`predicates - ${predicateName}`, () => { 28 | it("should have tests (valid samples)", () => { 29 | return expect(validValues).to.not.be.empty; 30 | }); 31 | 32 | it("should have tests (invalid samples)", () => { 33 | return expect(invalidValues).to.not.be.empty; 34 | }); 35 | 36 | it("should validate a value", () => { 37 | tests.forEach(test => { 38 | return expect(valido[predicateName](test.value, test.options)).to.equal( 39 | test.result 40 | ); 41 | }); 42 | }); 43 | 44 | it("should validate an optional value", () => { 45 | optionalValueTests.forEach(test => { 46 | expect(valido.optional[predicateName](null, test.options)).to.equal( 47 | true 48 | ); 49 | expect( 50 | valido.optional[predicateName](undefined, test.options) 51 | ).to.equal(true); 52 | 53 | if (test.value !== null && test.value !== undefined) { 54 | expect( 55 | valido.optional[predicateName](test.value, test.options) 56 | ).to.equal(test.result); 57 | } 58 | }); 59 | }); 60 | 61 | it("should validate a list of values", () => { 62 | tests.forEach(test => { 63 | const values = [test.value, test.value]; 64 | return expect(valido.all[predicateName](values, test.options)).to.equal( 65 | test.result 66 | ); 67 | }); 68 | }); 69 | 70 | it("should validate an empty list to true", () => { 71 | return expect(valido.all[predicateName]([])).to.equal(true); 72 | }); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const isUrl = require('./predicates/url'); 4 | const isUri = require('./predicates/uri'); 5 | const isWebUrl = require('./predicates/webUrl'); 6 | const isHexColor = require('./predicates/hexColor'); 7 | const isString = require('./predicates/string'); 8 | const isArray = require('./predicates/array'); 9 | const isNull = require('./predicates/null'); 10 | const isUndefined = require('./predicates/undefined'); 11 | const isExisty = require('./predicates/existy'); 12 | const isInteger = require('./predicates/integer'); 13 | const isFinite = require('./predicates/finite'); 14 | const isNatural = require('./predicates/natural'); 15 | const isNumber = require('./predicates/number'); 16 | const isBuffer = require('./predicates/buffer'); 17 | const isBoolean = require('./predicates/boolean'); 18 | const isFunction = require('./predicates/function'); 19 | const isPlainObject = require('./predicates/plainObject'); 20 | const isStream = require('./predicates/stream'); 21 | const isDate = require('./predicates/date'); 22 | const isEmail = require('./predicates/email'); 23 | 24 | const predicates = { 25 | uri: isUri, 26 | url: isUrl, 27 | webUrl: isWebUrl, 28 | hexColor: isHexColor, 29 | string: isString, 30 | array: isArray, 31 | existy: isExisty, 32 | integer: isInteger, 33 | finite: isFinite, 34 | natural: isNatural, 35 | number: isNumber, 36 | buffer: isBuffer, 37 | boolean: isBoolean, 38 | plainObject: isPlainObject, 39 | date: isDate, 40 | null: isNull, 41 | undefined: isUndefined, 42 | function: isFunction, 43 | stream: isStream, 44 | email: isEmail, 45 | }; 46 | 47 | const api = { all: {}, optional: {} }; 48 | 49 | // Build API 50 | Object.getOwnPropertyNames(predicates).forEach((predicateName) => { 51 | const predicate = predicates[predicateName]; 52 | api[predicateName] = predicate; 53 | api.all[predicateName] = (values, options) => validateAll(values, predicate, options); 54 | api.optional[predicateName] = (value, options) => validateOptional(value, predicate, options); 55 | }); 56 | 57 | /** 58 | * Validates a list of values 59 | * 60 | * @param {Array<*>} values - Values 61 | * @param {function} predicate - predicate 62 | * @param {object} options - Options 63 | * @returns {Boolean} 64 | */ 65 | function validateAll(values, predicate, options) { 66 | if (!isArray(values)) { 67 | return false; 68 | } 69 | 70 | return values.every(value => predicate(value, options)); 71 | } 72 | 73 | /** 74 | * Validates an optional values 75 | * An optional value will always validate to true if null/undefined 76 | * 77 | * @param {*} value - Value 78 | * @param {function} predicate - predicate 79 | * @param {object} options - Options 80 | * @returns {Boolean} 81 | */ 82 | function validateOptional(value, predicate, options) { 83 | if (!isExisty(value)) { 84 | return true; 85 | } 86 | 87 | return predicate(value, options); 88 | } 89 | 90 | module.exports = api; 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Valido 2 | General purpose check and validation library. 3 | 4 | The focus is on providing selected, well tested checks and a convenient API. The library is inspired by other projects, like is_js and joi in terms of the API, but completely written from ground up to be easily extendable and testable. 5 | 6 | Contributions are welcome. 7 | 8 | ## Installing 9 | `npm install valido` 10 | 11 | ## Usage 12 | ```` 13 | const is = require('valido'); 14 | 15 | is.uri('http://www.test.com'); 16 | --> true 17 | 18 | is.all.uri(['http://www.test.com', 123]); 19 | --> false 20 | 21 | is.optional.uri(null); 22 | --> true 23 | 24 | is.optional.uri('http://www.test.com'); 25 | --> true 26 | 27 | is.optional.uri(123); 28 | --> false 29 | ```` 30 | 31 | ## API 32 | ### all 33 | Will return true if all elements in the list validate to true. Can be combined with all predicates. 34 | 35 | ```` 36 | is.all.number([007, 123]); 37 | --> true 38 | 39 | is.all.number(['abc', 123]); 40 | --> false 41 | ```` 42 | 43 | ### optional 44 | Will return true if the provided value is either null/undefined or validates to true. Can be combined with all predicates. 45 | 46 | ```` 47 | is.optional.number(null); 48 | --> true 49 | 50 | is.optional.number(123); 51 | --> true 52 | 53 | is.optional.number('abc'); 54 | --> false 55 | ```` 56 | --- 57 | 58 | ### array(value:any) 59 | Checks if value is an array. 60 | 61 | ```` 62 | is.array([]); 63 | --> true 64 | ```` 65 | 66 | ### boolean(value:any) 67 | Checks if value is a boolean. 68 | 69 | ```` 70 | is.boolean(true); 71 | --> true 72 | 73 | is.boolean(0); 74 | --> false 75 | ```` 76 | 77 | ### buffer(value:any) 78 | Checks if value is a buffer. 79 | 80 | ```` 81 | is.buffer(new Buffer('abc')); 82 | --> true 83 | 84 | is.buffer('abc'); 85 | --> false 86 | ```` 87 | 88 | ### date(value:any) 89 | Checks if value is a date object. 90 | 91 | ```` 92 | is.date(new Date()); 93 | --> true 94 | 95 | is.date('2016-01-01'); 96 | --> false 97 | ```` 98 | 99 | ### email(value:any) 100 | Checks if value is a valid email according to [link](https://www.w3.org/TR/html5/forms.html#valid-e-mail-address "W3C recommendation"). 101 | 102 | ```` 103 | is.email('bob@test.com'); 104 | --> true 105 | 106 | is.email('test.com'); 107 | --> false 108 | ```` 109 | 110 | ### existy(value:any) 111 | Checks if value is not null and not undefined. 112 | 113 | ```` 114 | is.existy(123); 115 | --> true 116 | 117 | is.existy(null); 118 | --> false 119 | ```` 120 | 121 | ### finite(value:any) 122 | Checks if value is finite. 123 | 124 | ```` 125 | is.finite(123); 126 | --> true 127 | 128 | is.finite(2e64); 129 | --> true 130 | 131 | is.finite(Infinity); 132 | --> false 133 | ```` 134 | 135 | ### function(value:any) 136 | Checks if value is a function. 137 | 138 | ```` 139 | is.function(() => {}); 140 | --> true 141 | 142 | is.function(function(){}); 143 | --> true 144 | 145 | is.function('function'); 146 | --> false 147 | ```` 148 | 149 | ### hexColor(value:any) 150 | Checks if value is a hex color. 151 | 152 | ```` 153 | is.hexColor('#ff3366'); 154 | --> true 155 | 156 | is.hexColor('#fff'); 157 | --> true 158 | 159 | is.hexColor('cc33cc'); 160 | --> false 161 | 162 | is.hexColor('fff'); 163 | --> false 164 | ```` 165 | 166 | ### integer(value:any) 167 | Checks if value is an integer. 168 | 169 | ```` 170 | is.integer(123); 171 | --> true 172 | 173 | is.integer(-1); 174 | --> true 175 | 176 | is.integer(2e64); 177 | --> true 178 | 179 | is.integer(1.1); 180 | --> false 181 | ```` 182 | 183 | ### natural(value:any, option:object) 184 | Checks if value is a natural number. 185 | 186 | ```` 187 | is.natural(123); 188 | --> true 189 | 190 | is.natural(0); 191 | --> true 192 | 193 | is.natural(0, { disallowZero: true }); 194 | --> false 195 | 196 | is.natural(1.1); 197 | --> false 198 | 199 | is.natural(-1); 200 | --> false 201 | ```` 202 | 203 | ### null(value:any) 204 | Checks if value is `null`. 205 | 206 | ```` 207 | is.null(null); 208 | --> true 209 | 210 | is.null(0); 211 | --> false 212 | 213 | is.null(undefined); 214 | --> false 215 | ```` 216 | 217 | ### number(value:any) 218 | Checks if value is of type `number`. 219 | 220 | ```` 221 | is.number(1); 222 | --> true 223 | 224 | is.number(Math.PI); 225 | --> true 226 | 227 | is.number(NaN); 228 | --> true 229 | 230 | is.number(Infinity); 231 | --> true 232 | 233 | is.number(2e64); 234 | --> true 235 | 236 | is.number('1'); 237 | --> false 238 | ```` 239 | 240 | ### plainObject(value:any) 241 | Checks if value is a plain object (prototype is Object). 242 | 243 | ```` 244 | is.plainObject({}); 245 | --> true 246 | 247 | is.plainObject(Object.assign({})); 248 | --> true 249 | 250 | is.plainObject(new Object({}); 251 | --> true 252 | 253 | is.plainObject(function(){}); 254 | --> false 255 | ```` 256 | 257 | ### stream(value:any) 258 | Checks if value is a stream. 259 | 260 | ```` 261 | const Stream = require('stream'); 262 | 263 | is.stream(new Stream.Readable()); 264 | --> true 265 | 266 | is.stream(new Stream.Writable()); 267 | --> true 268 | 269 | is.stream(new Stream.Transform()); 270 | --> true 271 | 272 | is.stream(new Stream.PassThrough()); 273 | --> true 274 | 275 | is.stream(new Stream.Duplex()); 276 | --> true 277 | 278 | is.stream(123); 279 | --> false 280 | ```` 281 | 282 | ### string(value:any, options:object) 283 | Checks if value is a string. 284 | 285 | ```` 286 | is.string('abc'); 287 | --> true 288 | 289 | is.string('abc', { startsWith: 'a' }); 290 | --> true 291 | 292 | is.string('abc', { endsWith: 'b' }); 293 | --> false 294 | 295 | is.string(123); 296 | --> false 297 | ```` 298 | 299 | ### undefined(value:any) 300 | Checks if value is undefined. 301 | 302 | ```` 303 | is.undefined(undefined); 304 | --> true 305 | 306 | is.undefined(null); 307 | --> false 308 | ```` 309 | 310 | ### uri(value:any, options:object) 311 | Checks if value is a URI according to RFC 3986. 312 | 313 | ```` 314 | is.uri('https://8.8.8.8:3128'); 315 | --> true 316 | 317 | is.uri('https://localhost:80'); 318 | --> true 319 | 320 | is.uri('mongodb://db.server.com:1234'); 321 | --> true 322 | 323 | is.uri('https://user:pass@www.test.com:8080/index.html?param=2&yy=abc'); 324 | --> true 325 | 326 | is.uri('https://www.test.com/', { endsWith: '/' }); 327 | --> true 328 | 329 | is.uri('https://www.test.com/', { startsWith: 'https://www.other.com' }); 330 | --> false 331 | 332 | is.uri('google.com'); 333 | --> false 334 | ```` -------------------------------------------------------------------------------- /lib/rfc3986.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const rfc3986 = {}; 4 | 5 | /** 6 | * elements separated by forward slash ("/") are alternatives. 7 | */ 8 | const or = '|'; 9 | 10 | /** 11 | * DIGIT = %x30-39 ; 0-9 12 | */ 13 | const digit = '0-9'; 14 | const digitOnly = `[${digit}]`; 15 | 16 | /** 17 | * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z 18 | */ 19 | const alpha = 'a-zA-Z'; 20 | const alphaOnly = `[${alpha}]`; 21 | 22 | /** 23 | * cidr = DIGIT ; 0-9 24 | * / %x31-32 DIGIT ; 10-29 25 | * / "3" %x30-32 ; 30-32 26 | */ 27 | rfc3986.cidr = `${digitOnly}${or}[1-2]${digitOnly}${or}3[0-2]`; 28 | 29 | /** 30 | * HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" 31 | */ 32 | const hexDigit = `${digit}A-Fa-f`; 33 | const hexDigitOnly = `[${hexDigit}]`; 34 | 35 | /** 36 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 37 | */ 38 | const unreserved = `${alpha}${digit}-\\._~`; 39 | 40 | /** 41 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" 42 | */ 43 | const subDelims = '!\\$&\'\\(\\)\\*\\+,;='; 44 | 45 | /** 46 | * pct-encoded = "%" HEXDIG HEXDIG 47 | */ 48 | const pctEncoded = `%${hexDigit}`; 49 | 50 | /** 51 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 52 | */ 53 | const pchar = `${unreserved}${pctEncoded}${subDelims}:@`; 54 | const pcharOnly = `[${pchar}]`; 55 | 56 | /** 57 | * Rule to support zero-padded addresses. 58 | */ 59 | const zeroPad = '0?'; 60 | 61 | /** 62 | * dec-octet = DIGIT ; 0-9 63 | * / %x31-39 DIGIT ; 10-99 64 | * / "1" 2DIGIT ; 100-199 65 | * / "2" %x30-34 DIGIT ; 200-249 66 | * / "25" %x30-35 ; 250-255 67 | */ 68 | const decOctect = `(?:${zeroPad}${zeroPad}${digitOnly}${or}${zeroPad}[1-9]${digitOnly}${or}1${digitOnly}${digitOnly}${or}2[0-4]${digitOnly}${or}25[0-5])`; // eslint-disable-line max-len 69 | 70 | /** 71 | * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet 72 | */ 73 | rfc3986.IPv4address = `(?:${decOctect}\\.){3}${decOctect}`; 74 | 75 | /** 76 | * h16 = 1*4HEXDIG ; 16 bits of address represented in hexadecimal 77 | * ls32 = ( h16 ":" h16 ) / IPv4address ; least-significant 32 bits of address 78 | * IPv6address = 6( h16 ":" ) ls32 79 | * / "::" 5( h16 ":" ) ls32 80 | * / [ h16 ] "::" 4( h16 ":" ) ls32 81 | * / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 82 | * / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 83 | * / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 84 | * / [ *4( h16 ":" ) h16 ] "::" ls32 85 | * / [ *5( h16 ":" ) h16 ] "::" h16 86 | * / [ *6( h16 ":" ) h16 ] "::" 87 | */ 88 | const h16 = `${hexDigitOnly}{1,4}`; 89 | const ls32 = `(?:${h16}:${h16}|${rfc3986.IPv4address})`; 90 | const IPv6SixHex = `(?:${h16}:){6}${ls32}`; 91 | const IPv6FiveHex = `::(?:${h16}:){5}${ls32}`; 92 | const IPv6FourHex = `(?:${h16})?::(?:${h16}:){4}${ls32}`; 93 | const IPv6ThreeHex = `(?:(?:${h16}:){0,1}${h16})?::(?:${h16}:){3}${ls32}`; 94 | const IPv6TwoHex = `(?:(?:${h16}:){0,2}${h16})?::(?:${h16}:){2}${ls32}`; 95 | const IPv6OneHex = `(?:(?:${h16}:){0,3}${h16})?::${h16}:${ls32}`; 96 | const IPv6NoneHex = `(?:(?:${h16}:){0,4}${h16})?::${ls32}`; 97 | const IPv6NoneHex2 = `(?:(?:${h16}:){0,5}${h16})?::${h16}`; 98 | const IPv6NoneHex3 = `(?:(?:${h16}:){0,6}${h16})?::`; 99 | rfc3986.IPv6address = `(?:${IPv6SixHex}${or}${IPv6FiveHex}${or}${IPv6FourHex}${or}${IPv6ThreeHex}${or}${IPv6TwoHex}${or}${IPv6OneHex}${or}${IPv6NoneHex}${or}${IPv6NoneHex2}${or}${IPv6NoneHex3})`; // eslint-disable-line max-len 100 | 101 | /** 102 | * IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) 103 | */ 104 | rfc3986.IPvFuture = `v${hexDigitOnly}+\\.[${unreserved}${subDelims}:]+`; 105 | 106 | /** 107 | * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) 108 | */ 109 | rfc3986.scheme = `${alphaOnly}[${alpha}${digit}+-\\.]*`; 110 | 111 | /** 112 | * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) 113 | */ 114 | const userinfo = `[${unreserved}${pctEncoded}${subDelims}:]*`; 115 | 116 | /** 117 | * IP-literal = "[" ( IPv6address / IPvFuture ) "]" 118 | */ 119 | const IPLiteral = `\\[(?:${rfc3986.IPv6address}${or}${rfc3986.IPvFuture})\\]`; 120 | 121 | /** 122 | * reg-name = *( unreserved / pct-encoded / sub-delims ) 123 | */ 124 | const regName = `[${unreserved}${pctEncoded}${subDelims}]{0,255}`; 125 | 126 | /** 127 | * host = IP-literal / IPv4address / reg-name 128 | */ 129 | const host = `(?:${IPLiteral}${or}${rfc3986.IPv4address}${or}${regName})`; 130 | 131 | /** 132 | * port = *DIGIT 133 | */ 134 | const port = `${digitOnly}*`; 135 | 136 | /** 137 | * authority = [ userinfo "@" ] host [ ":" port ] 138 | */ 139 | const authority = `(?:${userinfo}@)?${host}(?::${port})?`; 140 | 141 | /** 142 | * segment = *pchar 143 | * segment-nz = 1*pchar 144 | * path = path-abempty ; begins with "/" or is empty 145 | * / path-absolute ; begins with "/" but not "//" 146 | * / path-noscheme ; begins with a non-colon segment 147 | * / path-rootless ; begins with a segment 148 | * / path-empty ; zero characters 149 | * path-abempty = *( "/" segment ) 150 | * path-absolute = "/" [ segment-nz *( "/" segment ) ] 151 | * path-rootless = segment-nz *( "/" segment ) 152 | */ 153 | const segment = `${pcharOnly}*`; 154 | const segmentNz = `${pcharOnly}+`; 155 | const segmentNzNc = `[${unreserved}${pctEncoded}${subDelims}@]+`; 156 | const pathEmpty = ''; 157 | const pathAbEmpty = `(?:\\/${segment})*`; 158 | const pathAbsolute = `\\/(?:${segmentNz}${pathAbEmpty})?`; 159 | const pathRootless = segmentNz + pathAbEmpty; 160 | const pathNoScheme = segmentNzNc + pathAbEmpty; 161 | 162 | /** 163 | * hier-part = "//" authority path 164 | */ 165 | rfc3986.hierPart = `(?:(?:\\/\\/${authority}${pathAbEmpty})${or}${pathAbsolute}${or}${pathRootless})`; // eslint-disable-line max-len 166 | 167 | /** 168 | * relative-part = "//" authority path-abempty 169 | * / path-absolute 170 | * / path-noscheme 171 | * / path-empty 172 | */ 173 | rfc3986.relativeRef = `(?:(?:\\/\\/${authority}${pathAbEmpty})${or}${pathAbsolute}${or}${pathNoScheme}${or}${pathEmpty})`; // eslint-disable-line max-len 174 | 175 | /** 176 | * query = *( pchar / "/" / "?" ) 177 | */ 178 | // Finish matching either at the fragment part or end of the line. 179 | rfc3986.query = `[${pchar}\\/\\?]*(?=#|$)`; 180 | 181 | /** 182 | * fragment = *( pchar / "/" / "?" ) 183 | */ 184 | rfc3986.fragment = `[${pchar}\\/\\?]*`; 185 | 186 | const prefix = `(?:${rfc3986.scheme}:${rfc3986.hierPart})`; 187 | const re = new RegExp(`^${prefix}(?:\\?${rfc3986.query})?(?:#${rfc3986.fragment})?$`); 188 | 189 | module.exports = re; 190 | --------------------------------------------------------------------------------