| // Copyright (c) 2012, Mark Cavage. All rights reserved. |
| // Copyright 2015 Joyent, Inc. |
| |
| var assert = require('assert'); |
| var Stream = require('stream').Stream; |
| var util = require('util'); |
| |
| |
| ///--- Globals |
| |
| /* JSSTYLED */ |
| var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/; |
| |
| |
| ///--- Internal |
| |
| function _capitalize(str) { |
| return (str.charAt(0).toUpperCase() + str.slice(1)); |
| } |
| |
| function _toss(name, expected, oper, arg, actual) { |
| throw new assert.AssertionError({ |
| message: util.format('%s (%s) is required', name, expected), |
| actual: (actual === undefined) ? typeof (arg) : actual(arg), |
| expected: expected, |
| operator: oper || '===', |
| stackStartFunction: _toss.caller |
| }); |
| } |
| |
| function _getClass(arg) { |
| return (Object.prototype.toString.call(arg).slice(8, -1)); |
| } |
| |
| function noop() { |
| // Why even bother with asserts? |
| } |
| |
| |
| ///--- Exports |
| |
| var types = { |
| bool: { |
| check: function (arg) { return typeof (arg) === 'boolean'; } |
| }, |
| func: { |
| check: function (arg) { return typeof (arg) === 'function'; } |
| }, |
| string: { |
| check: function (arg) { return typeof (arg) === 'string'; } |
| }, |
| object: { |
| check: function (arg) { |
| return typeof (arg) === 'object' && arg !== null; |
| } |
| }, |
| number: { |
| check: function (arg) { |
| return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg); |
| } |
| }, |
| buffer: { |
| check: function (arg) { return Buffer.isBuffer(arg); }, |
| operator: 'Buffer.isBuffer' |
| }, |
| array: { |
| check: function (arg) { return Array.isArray(arg); }, |
| operator: 'Array.isArray' |
| }, |
| stream: { |
| check: function (arg) { return arg instanceof Stream; }, |
| operator: 'instanceof', |
| actual: _getClass |
| }, |
| date: { |
| check: function (arg) { return arg instanceof Date; }, |
| operator: 'instanceof', |
| actual: _getClass |
| }, |
| regexp: { |
| check: function (arg) { return arg instanceof RegExp; }, |
| operator: 'instanceof', |
| actual: _getClass |
| }, |
| uuid: { |
| check: function (arg) { |
| return typeof (arg) === 'string' && UUID_REGEXP.test(arg); |
| }, |
| operator: 'isUUID' |
| } |
| }; |
| |
| function _setExports(ndebug) { |
| var keys = Object.keys(types); |
| var out; |
| |
| /* re-export standard assert */ |
| if (process.env.NODE_NDEBUG) { |
| out = noop; |
| } else { |
| out = function (arg, msg) { |
| if (!arg) { |
| _toss(msg, 'true', arg); |
| } |
| }; |
| } |
| |
| /* standard checks */ |
| keys.forEach(function (k) { |
| if (ndebug) { |
| out[k] = noop; |
| return; |
| } |
| var type = types[k]; |
| out[k] = function (arg, msg) { |
| if (!type.check(arg)) { |
| _toss(msg, k, type.operator, arg, type.actual); |
| } |
| }; |
| }); |
| |
| /* optional checks */ |
| keys.forEach(function (k) { |
| var name = 'optional' + _capitalize(k); |
| if (ndebug) { |
| out[name] = noop; |
| return; |
| } |
| var type = types[k]; |
| out[name] = function (arg, msg) { |
| if (arg === undefined || arg === null) { |
| return; |
| } |
| if (!type.check(arg)) { |
| _toss(msg, k, type.operator, arg, type.actual); |
| } |
| }; |
| }); |
| |
| /* arrayOf checks */ |
| keys.forEach(function (k) { |
| var name = 'arrayOf' + _capitalize(k); |
| if (ndebug) { |
| out[name] = noop; |
| return; |
| } |
| var type = types[k]; |
| var expected = '[' + k + ']'; |
| out[name] = function (arg, msg) { |
| if (!Array.isArray(arg)) { |
| _toss(msg, expected, type.operator, arg, type.actual); |
| } |
| var i; |
| for (i = 0; i < arg.length; i++) { |
| if (!type.check(arg[i])) { |
| _toss(msg, expected, type.operator, arg, type.actual); |
| } |
| } |
| }; |
| }); |
| |
| /* optionalArrayOf checks */ |
| keys.forEach(function (k) { |
| var name = 'optionalArrayOf' + _capitalize(k); |
| if (ndebug) { |
| out[name] = noop; |
| return; |
| } |
| var type = types[k]; |
| var expected = '[' + k + ']'; |
| out[name] = function (arg, msg) { |
| if (arg === undefined || arg === null) { |
| return; |
| } |
| if (!Array.isArray(arg)) { |
| _toss(msg, expected, type.operator, arg, type.actual); |
| } |
| var i; |
| for (i = 0; i < arg.length; i++) { |
| if (!type.check(arg[i])) { |
| _toss(msg, expected, type.operator, arg, type.actual); |
| } |
| } |
| }; |
| }); |
| |
| /* re-export built-in assertions */ |
| Object.keys(assert).forEach(function (k) { |
| if (k === 'AssertionError') { |
| out[k] = assert[k]; |
| return; |
| } |
| if (ndebug) { |
| out[k] = noop; |
| return; |
| } |
| out[k] = assert[k]; |
| }); |
| |
| /* export ourselves (for unit tests _only_) */ |
| out._setExports = _setExports; |
| |
| return out; |
| } |
| |
| module.exports = _setExports(process.env.NODE_NDEBUG); |