'use strict'; // Built-in types var types = [ 'object', 'number', 'string', 'symbol', 'boolean', 'date', 'function', // Weird to expose this ]; function normalize(coercer, value) { if (typeof value === 'function') { if (coercer === 'function') { return value; } value = value.apply(this, slice(arguments, 2)); } return coerce(this, coercer, value); } function coerce(ctx, coercer, value) { // Handle built-in types if (typeof coercer === 'string') { if (coerce[coercer]) { return coerce[coercer].call(ctx, value); } return typeOf(coercer, value); } // Handle custom coercer if (typeof coercer === 'function') { return coercer.call(ctx, value); } // Array of coercers, try in order until one returns a non-null value var result; coercer.some(function(coercer) { result = coerce(ctx, coercer, value); return result != null; }); return result; } coerce.string = function(value) { if (value != null && typeof value === 'object' && typeof value.toString === 'function') { value = value.toString(); } return typeOf('string', primitive(value)); }; coerce.number = function(value) { return typeOf('number', primitive(value)); }; coerce.boolean = function(value) { return typeOf('boolean', primitive(value)); }; coerce.date = function(value) { value = primitive(value); if (typeof value === 'number' && !isNaN(value) && isFinite(value)) { return new Date(value); } }; function typeOf(type, value) { if (typeof value === type) { return value; } } function primitive(value) { if (value != null && typeof value === 'object' && typeof value.valueOf === 'function') { value = value.valueOf(); } return value; } function slice(value, from) { return Array.prototype.slice.call(value, from); } // Add methods for each type types.forEach(function(type) { // Make it an array for easier concat var typeArg = [type]; normalize[type] = function() { var args = slice(arguments); return normalize.apply(this, typeArg.concat(args)); }; }); module.exports = normalize;