UNPKG

node-util

Version:
1,217 lines (915 loc) 24.5 kB
"use strict"; var fs = require("fs"), crypto = require("crypto"); var util = require("util"), cwd = process.cwd(), ObjectProto = Object.prototype, toString = ObjectProto.toString, hasOwnProperty = ObjectProto.hasOwnProperty, defineProperty = Object.defineProperty, slice = Array.prototype.slice, isArray = Array.isArray, UID_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", UID_CHARS_LENGTH = UID_CHARS.length, SIGN_REPLACER = /\=+$/, FORMAT_REGEX = /%[sdj%]/g; function isEmpty(obj) { if (obj === null || obj === undefined) return true; if (isNumber(obj)) return false; if (isArray(obj) || isString(obj)) return obj.length === 0; for (var key in obj) if (has(obj, key)) return false; return true; } util.isEmpty = isEmpty; function isObject(obj) { return obj === Object(obj); } util.isObject = isObject; function isArrayLike(obj) { return typeof(obj) === "object" && typeof(obj.length) === "number"; } util.isArrayLike = isArrayLike; util.isArray = isArray; function isArguments(obj) { return toString.call(obj) === "[object Arguments]"; } util.isArguments = isArguments; function isFunction(obj) { return typeof(obj) === "function"; } util.isFunction = isFunction; function isString(obj) { return toString.call(obj) === "[object String]"; } util.isString = isString; function isNumber(obj) { return toString.call(obj) === "[object Number]"; } util.isNumber = isNumber; function isDecimal(obj) { return isNumber(obj) && obj % 1 !== 0; } util.isDecimal = isDecimal; function isInteger(obj) { return isNumber(obj) && obj % 1 === 0; } util.isInteger = isInteger; function isDate(obj) { return toString.call(obj) === "[object Date]"; } util.isDate = isDate; function isRegExp(obj) { return toString.call(obj) === "[object RegExp]"; } util.isRegExp = isRegExp; util.isFinite = isFinite; util.isNaN = isNaN; function isBoolean(obj) { return obj === true || obj === false || toString.call(obj) === "[object Boolean]"; } util.isBoolean = isBoolean; function isNull(obj) { return obj === null; } util.isNull = isNull; function isUndefined(obj) { return obj === void 0; } util.isUndefined = isUndefined; function has(obj, key) { return hasOwnProperty.call(obj, key); } util.has = has; function extend(parent, child) { child.prototype = Object.create(parent.prototype); child.prototype.constructor = child; return child; } util.extend = extend; function format(fmt) { var i = 1, args = arguments, len = args.length; return String(fmt).replace(FORMAT_REGEX, function(x) { if (x === "%%") return "%"; if (i >= len) return x; if (x === "%s") { return String(args[i++]); } else if (x === "%d") { return Number(args[i++]); } else if (x === "%j") { try { return JSON.stringify(args[i++]); } catch (e) { return "[Circular]"; } } else { return x; } }); } util.format = format; function invert(obj) { var result = {}; for (key in obj) result[obj[key]] = key; return result; } util.invert = invert; function arraySubtract(obj, sub) { var i, j; for (i = sub.length; i--;) for (j = obj.length; j--;) { if (obj[i] === sub[j]) obj.splice(i, 1); } return obj; } util.arraySubtract = arraySubtract; function flattenArray(array, out) { isArray(out) || (out = []); var item, i, il; for (i = 0, il = array.length; i < il; i++) { if (isArray((item = array[i]))) { flattenArray(item, out); } else { out.push(item); } } return out; } util.flattenArray = flattenArray; function unique(array, out) { isArray(out) || (out = []); var visted = [], item, i = 0, il = array.length; for (; i < il; i++) { if (visted.indexOf((item = array[i])) !== -1) continue; visted.push(item); out.push(item); } return out; } util.unique = unique; function intersection() { return unique(flattenArray(slice.call(arguments))); } util.intersection = intersection; function prng(length) { length || (length = 24); var out = "", i; for (i = length; i--;) out += UID_CHARS[Math.floor(Math.random() * UID_CHARS_LENGTH)]; return out; } util.prng = prng; function merge(obj, add) { for (var key in add) { if (obj[key] == undefined) obj[key] = add[key]; } return obj; }; util.merge = merge; function override(obj, add) { for (var key in add) { if (add[key] != undefined) obj[key] = add[key]; } return obj; }; util.override = override; function copy(obj) { var out, i, il; if (typeof(obj) !== "object") return obj; if (isArrayLike(obj)) { out = []; for (i = 0, il = obj.length; i < il; i++) out.push(copy(obj[i])); } else if (isObject(obj)) { out = {}; for (var key in obj) out[key] = copy(obj[key]); } else { out = obj; } return out; }; util.copy = copy; function clear(obj) { for (var key in obj) delete obj[key]; return obj; }; util.clear = clear; util.keys = Object.keys; function each(obj, iterator, ctx) { if (obj == null) return; var i, il, objKeys; if (isArrayLike(obj)) { if (ctx) { for (i = 0, il = obj.length; i < il; i++) { if (iterator.call(ctx, obj[i], i, obj) === false) return; } } else { for (i = 0, il = obj.length; i < il; i++) { if (iterator(obj[i], i, obj) === false) return; } } } else if (isObject(obj)) { objKeys = keys(obj); if (ctx) { for (i = 0, il = objKeys.length; i < il; i++) { if (iterator.call(ctx, obj[objKeys[i]], objKeys[i], obj) === false) return; } } else { for (i = 0, il = objKeys.length; i < il; i++) { if (iterator(obj[objKeys[i]], objKeys[i], obj) === false) return; } } } else { throw new TypeError("each(obj, iterator, ctx) obj must be ArrayLike or an Object"); } } util.each = each; function async(tasks, callback) { var i = 0; if (!isArray(tasks) || !callback) { tasks = slice.call(arguments); callback = tasks.pop(); } if (!isFunction(callback)) { throw new TypeError("async(tasks, ..., callback) last arguments is not a function"); return; } function iterate(err) { var fn = tasks[i++]; if (err || !isFunction(fn)) { callback(err); return; } try { fn(iterate); } catch (e) { callback(e); } } iterate(); } util.async = async; var escapeMap = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#x27;" }, unescapeMap = { "&amp;": "&", "&lt;": "<", "&gt;": ">", "&quot;": '"', "&#x27;": "'" }, ESCAPE_REGEX = new RegExp("[" + Object.keys(escapeMap).join("") + "]", "g"), UNESCAPE_REGEX = new RegExp("(" + Object.keys(unescapeMap).join("|") + ")", "g"); function escape_filter(match) { return escapeMap[match]; } function escape(str) { if (str == null) return ""; return ("" + str).replace(ESCAPE_REGEX, escape_filter); } util.escape = escape; function unescape_filter(match) { return unescapeMap[match]; } function unescape(str) { if (str == null) return ""; return ("" + str).replace(UNESCAPE_REGEX, unescape_filter); } util.unescape = unescape; var queryStringParse_regexp = /\+/g; function queryStringParse(qs, sep, eq, options) { sep = sep || "&"; eq = eq || "="; var obj = {}, regexp = queryStringParse_regexp, maxKeys = 1000, decode = decodeURIComponent, len, i; if (!isString(qs) || qs.length === 0) return obj; qs = qs.split(sep); var maxKeys = 1000; if (options && isNumber(options.maxKeys)) { maxKeys = options.maxKeys; } len = qs.length; if (maxKeys > 0 && len > maxKeys) len = maxKeys; if (options && isFunction(options.decodeURIComponent)) decode = options.decodeURIComponent; for (i = 0; i < len; i++) { var x = qs[i].replace(regexp, "%20"), idx = x.indexOf(eq), kstr, vstr, k, v, tmp; if (idx >= 0) { kstr = x.substr(0, idx); vstr = x.substr(idx + 1); } else { kstr = x; vstr = ''; } try { k = decode(kstr); v = decode(vstr); if ((tmp = +v)) v = tmp; } catch (e) { continue; } if (!has(obj, k)) { obj[k] = v; } else if (isArray(obj[k])) { obj[k].push(v); } else { obj[k] = [obj[k], v]; } } return obj; } util.queryStringParse = util.queryStringDecode = queryStringParse; function stringifyPrimitive(v) { if (isString(v)) return v; if (isBoolean(v)) return v ? "true" : "false"; if (isNumber(v)) return isFinite(v) ? v : ""; return ''; }; function queryStringStringify(obj, sep, eq, options) { sep = sep || "&"; eq = eq || "="; if (isNull(obj)) { obj = undefined; } var encode = encodeURIComponent; if (options && isFunction(options.encodeURIComponent)) encode = options.encodeURIComponent; if (isObject(obj)) { return Object.keys(obj).map(function(k) { var ks = encode(stringifyPrimitive(k)) + eq; if (isArray(obj[k])) { return obj[k].map(function(v) { return ks + encode(stringifyPrimitive(v)); }).join(sep); } else { return ks + encode(stringifyPrimitive(obj[k])); } }).join(sep); } return ""; } util.queryStringStringify = util.queryStringEncode = queryStringStringify; function template(text, data, settings) { var render, escapes = util.templateEscapes, escaper = util.templateEscaper, start, end, match = "([\\s\\S]+?)", evaluate, interpolate, escape, index = 0, source = "__p+='"; settings = merge((settings || {}), util.templateSettings); start = settings.start; end = settings.end; evaluate = start + match + end; interpolate = start + settings.interpolate + match + end; escape = start + settings.escape + match + end; text.replace(new RegExp(escape + "|" + interpolate + "|" + evaluate + "|$", "g"), function(match, escape, interpolate, evaluate, offset) { source += text.slice(index, offset).replace(escaper, function(match) { return '\\' + escapes[match]; }); if (escape) source += "'+\n((__t=(" + escape + "))==null?'':escape(__t))+\n'"; if (interpolate) source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; if (evaluate) source += "';\n" + evaluate + "\n__p+='"; index = offset + match.length; return match; }); source += "';\n"; if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; source = "var __t,__p='',__j=Array.prototype.join, print=function(){__p+=__j.call(arguments,'');};\n" + source + "return __p;\n"; try { render = new Function(settings.variable || 'obj', source); } catch (e) { e.source = source; throw e; } if (data) return render(data); function temp(data) { return render.call(this, data); }; temp.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; return temp; } util.template = template; util.templateEscaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; util.templateSettings = { start: "<%", end: "%>", interpolate: "=", escape: "-" }; util.templateEscapes = { "'": "'", "\\": "\\", "\r": "r", "\n": "n", "\t": "t", "\u2028": "u2028", "\u2029": "u2029" }; function renderFile(pathname, data, settings, callback) { data || (data = {}); if (isFunction(settings)) { callback = settings; settings = {}; } readFile(pathname, function(err, text) { if (err) { callback(err); return; } var out; try { out = template(text, data, settings); } catch (e) { callback(e); return; } callback(null, out); }); } util.renderFile = renderFile; function uid(length) { length || (length = 24); var out = "", bytes = crypto.pseudoRandomBytes(length), i; for (i = length; i--;) out += UID_CHARS[bytes[i] % UID_CHARS_LENGTH]; return out; } util.uid = uid; function md5(str, encoding) { return crypto.createHash("md5").update(str, "utf8").digest(encoding || "hex"); } util.md5 = md5; function signSecret(value, secret) { return value + "." + crypto.createHmac("sha256", secret).update(value).digest("base64").replace(SIGN_REPLACER, ""); } util.signSecret = signSecret; function unsignSecret(value, secret) { var str = value.slice(0, value.lastIndexOf(".")); return signSecret(str, secret) === value ? str : false; } util.unsignSecret = unsignSecret; util.diveDefaults = { all: false, recursive: true, files: true, directories: false }; function dive(dir, opts, action, complete) { if (isFunction(opts)) { complete = isFunction(action) ? action : function() {}; action = opts; opts = {}; } else if (!isFunction(complete)) { complete = function() {}; } if (isString(dir)) dir = cwd; merge(opts, util.diveDefaults); function doDive(dir) { fs.readdir(dir, function(err, files) { todo--; if (err) { action(err); return; } files.every(function(file) { if (opts.all || file[0] !== ".") { todo++; var fullPath = path.resolve(dir, file); fs.stat(fullPath, function(err, stat) { if (err) { todo--; return action(err) !== false; } if (stat) { if (stat.isDirectory()) { if (opts.directories) return action(null, fullPath) !== false; if (opts.recursive) doDive(fullPath); } else { if (opts.files) return action(null, fullPath) !== false; if (!--todo) complete(); } } return true; }); } return true; }); if (!todo) complete(); }); } var todo = 1; doDive(dir); } util.dive = dive; function diveSync(dir, opts, action) { if (isFunction(opts)) { action = opts; opts = {}; } if (isString(dir)) dir = cwd; merge(opts, util.diveDefaults); function doDive(dir) { var files; todo--; try { files = fs.readdirSync(dir); } catch (e) { return action(e) !== false; } return files.every(function(file) { if (opts.all || file[0] !== ".") { todo++; var fullPath = path.resolve(dir, file), stat; try { stat = fs.statSync(fullPath); } catch (e) { todo--; return action(e) !== false; } if (stat) { if (stat.isDirectory()) { if (opts.directories) return action(null, fullPath) !== false; if (opts.recursive) return doDive(fullPath) !== false; } else { if (opts.files) return action(null, fullPath) !== false; } } } return true; }); } var todo = 1; doDive(dir); } util.diveSync = diveSync; function fsCopy(dir, dest) { var stat; dir = path.resolve(cwd, dir); dest = path.resolve(cwd, dest); try { stat = fs.statSync(dir); } catch (e) {} if (!stat.isDirectory()) { var buffer; try { buffer = fs.readFileSync(dir); } catch (e) { console.warn(e); return; } mkdirPSync(path.dirname(dest)); fs.writeFileSync(dest, buffer); return; } diveSync(dir, function(err, fullPath) { if (err) { console.warn(err); return; } var pathName = fullPath.substring(dir.length), buffer; if (pathName[0] === "/") pathName = "." + pathName; pathName = path.resolve(dest, pathName); try { buffer = fs.readFileSync(fullPath); } catch (e) { console.warn(e); return; } mkdirPSync(path.dirname(pathName)); fs.writeFileSync(pathName, buffer); }); } util.fsCopy = fsCopy; function mkdirP(pathName, mode, callback, made) { if (isFunction(mode) || mode === undefined) { callback = mode; mode = 493; } if (!made) made = null; callback || (callback = function() {}); if (isString(mode)) mode = parseInt(mode, 8); fs.mkdir(pathName, mode, function(err) { if (!err) { made = made || pathName; callback(null, made); return; } switch (err.code) { case "ENOENT": mkdirP(path.dirname(pathName), mode, function(err, made) { if (err) { callback(err, made); } else { mkdirP(pathName, mode, callback, made); } }); break; default: fs.stat(pathName, function(er, stat) { if (er || !stat.isDirectory()) { callback(er, made); } else { callback(null, made); } }); break; } }); } util.mkdirP = mkdirP; function mkdirPSync(pathName, mode, made) { mode || (mode = 493); made || (made = null); if (isString(mode)) mode = parseInt(mode, 8); try { fs.mkdirSync(pathName, mode); made = made || pathName; } catch (err) { switch (err.code) { case "ENOENT": made = mkdirPSync(path.dirname(pathName), mode, made); mkdirPSync(pathName, mode, made); break; default: var stat; try { stat = fs.statSync(pathName); } catch (err) { throw err; } if (!stat.isDirectory()) throw err; break; } } return made; } util.mkdirPSync = mkdirPSync; util.validator = (function() { var EMAIL = /^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[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]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/, URL = /^(?!mailto:)(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))|localhost)(?::\d{2,5})?(?:\/[^\s]*)?$/i, EMPTY =/^[\s\t\r\n]*$/, IPv4 = /^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$/, IPv6 = /^::|^::1|^([a-fA-F0-9]{1,4}::?){1,7}([a-fA-F0-9]{1,4})$/, ALPHA = /^[a-zA-Z]+$/, ALPHA_NUMERIC = /^[a-zA-Z0-9]+$/, NUMERIC = /^[0-9]+$/, HEXA_DECIMAL = /^[0-9a-fA-F]+$/, HEX_COLOR = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/, INT = /^(?:-?(?:0|[1-9][0-9]*))$/, DECIMAL = /^(?:-?(?:[0-9]+))?(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/, UUID = /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i, UUID_V3 = /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, UUID_V4 = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, UUID_V5 = /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, REMOVE = /[^0-9]+/g, CREDIT_CARD = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/; function toDateTime(date) { if (date instanceof Date) return date; var intDate = Date.parse(date); if (isNaN(intDate)) return null; return new Date(intDate); } function toDate(date) { if (!(date instanceof Date)) date = toDateTime(date); if (!date) return null; return date; } var rules = { email: function(str) { return util.isString(str) && !!str.match(EMAIL); }, empty: util.isEmpty, notEmpty: function(str) { return !util.isEmpty(str); }, url: function(str) { return util.isString(str) && !!str.match(URL); }, ip: function(str) { if (!util.isString(str)) return false; if (rules.ipv4(str)) { return true; } else if (rules.ipv6(str)) { return true; } return false; }, ipv4: function(str) { if (!util.isString(str)) return false; if (IPv4.test(str)) { if (str.split(".").sort()[3] > 255) return false; return true; } return false; }, ipv6: function(str) { return util.isString(str) && IPv6.test(str); }, alpha: function(str) { return util.isString(str) && !!str.match(ALPHA); }, alphanumeric: function(str) { return util.isString(str) && !!str.match(ALPHA_NUMERIC); }, hexadecimal: function(str) { return util.isString(str) && !!str.match(HEXA_DECIMAL); }, hexcolor: function(str) { return util.isString(str) && !!str.match(HEX_COLOR); }, numeric: function(str) { return util.isNumber(str) || !!str.match(NUMERIC); }, lowercase: function(str) { return util.isString(str) && str === str.toLowerCase(); }, uppercase: function(str) { return util.isString(str) && str === str.toUpperCase(); }, json: function(str) { if (!util.isString(str)) return false; try{ var obj = JSON.parse(str); if (obj && util.isObject(obj) && obj !== null) { return true; } } catch(e) {} return false; }, int: util.isInteger, integer: util.isInteger, intstring: function(str) { return util.isString(str) && !!str.match(INT); }, integerstring: function(str) { return util.isString(str) && !!str.match(INT); }, decimal: util.isDecimal, float: util.isDecimal, decimalstring: function(str) { return util.isString(str) && !!str.match(DECIMAL); }, floatstring: function(str) { return util.isString(str) && !!str.match(DECIMAL); }, number: util.isNumber, finite: util.isFinite, falsey: function(x) { return x == false; }, truthy: function(x) { return x == true; }, divisibleby: function(str, num) { if (!util.isNumber(str)) return false; if (!util.isNumber(num)) num = +num; return str % num === 0; }, null: function(str) { return str === ""; }, notNull: function(str) { return str !== ""; }, equals: function(a, b) { return a === b; }, contains: function(str, elem) { return !!elem && ~str.indexOf(elem); }, notContains: function(str, elem) { return !!elem && str.indexOf(elem) === -1; }, regex: function(str, pattern, modifiers) { if (!util.isString(str)) str += ''; if (!util.isRegExp(pattern)) pattern = new RegExp(pattern, modifiers); return !!str.match(pattern); }, notRegex: function(str, pattern, modifiers) { if (!util.isString(str)) str += ''; if (!util.isRegExp(pattern)) pattern = new RegExp(pattern, modifiers); return !str.match(pattern); }, length: function(str, min, max) { var length = str.length; return length >= min && (max === undefined || length <= max); }, minLength: function(str, min) { if (util.isString(min)) min = +min; return str.length >= min; }, maxLength: function(str, max) { if (util.isString(max)) max = +max; return str.length <= max; }, uuid: function(str, version) { if (!version) return UUID.test(str); var pattern = UUID; if (version == 3 || version === "v3") { pattern = UUID_V3; } else if (version == 4 || version === "v4") { pattern = UUID_V4; } else if (version == 5 || version === "v5") { pattern = UUID_V5; } return pattern.test(str); }, uuidv3: function(str) { return UUID_V3.test(str); }, uuidv4: function(str) { return UUID_V4.test(str); }, uuidv5: function(str) { return UUID_V5.test(str); }, date: function(str) { return util.isDate(str) || !util.isNaN(Date.parse(str)); }, after: function(str, date) { date = date || new Date(); var origDate = toDate(str), compDate = toDate(date); return !(origDate && compDate && origDate <= compDate); }, before: function(str, date) { date = date || new Date(); var origDate = toDate(str), compDate = toDate(date); return !(origDate && compDate && origDate >= compDate); }, in: function(str, opts) { if (!opts || !util.isFunction(opts.indexOf)) return false; if (util.isArray(opts)) opts = opts.map(String); return !!~opts.indexOf(str); }, notIn: function(str, opts) { if (!opts || typeof(opts.indexOf) !== "function") return false; if (util.isArray(opts)) opts = opts.map(String); return opts.indexOf(str) === -1; }, min: function(str, min) { if (util.isString(str)) str = +str; if (util.isString(min)) min = +min; return str <= min; }, max: function(str, min) { if (util.isString(str)) str = +str; if (util.isString(min)) min = +min; return str >= min; }, creditcard: function(str) { var sanitized = str.replace(REMOVE, ""), sum = 0, digit, tmpNum, shouldDouble, i; if (sanitized.match(CREDIT_CARD) === null) return false; for (i = sanitized.length - 1; i >= 0; i--) { digit = sanitized.substring(i, (i + 1)); tmpNum = parseInt(digit, 10); if (shouldDouble) { tmpNum *= 2; if (tmpNum >= 10) { sum += ((tmpNum % 10) + 1); } else { sum += tmpNum; } } else { sum += tmpNum; } shouldDouble = !shouldDouble; } if ((sum % 10) === 0) return true; return false; } }; function validator(name, value) { var rule = rules[name], args; if (!rule) throw new Error("Unknown Rule "+ name); if (arguments.length > 2) { args = slice.call(arguments, 1); return rule.apply(rules, args); } return rule(value); } validator.rules = rules; return validator; }()); module.exports = util;