/** * @file Converts a JavaScript object to a primitive value. * @version 1.1.0 * @author Xotic750 * @copyright Xotic750 * @license {@link MIT} * @module to-primitive-x */ 'use strict'; var hasSymbols = require('has-symbol-support-x'); var isPrimitive = require('is-primitive'); var isDate = require('is-date-object'); var isSymbol = require('is-symbol'); var isFunction = require('is-function-x'); var requireObjectCoercible = require('require-object-coercible-x'); var isNil = require('is-nil-x'); var isUndefined = require('validate.io-undefined'); var symToPrimitive = hasSymbols && Symbol.toPrimitive; var symValueOf = hasSymbols && Symbol.prototype.valueOf; var toStringOrder = ['toString', 'valueOf']; var toNumberOrder = ['valueOf', 'toString']; var orderLength = 2; var ordinaryToPrimitive = function _ordinaryToPrimitive(O, hint) { requireObjectCoercible(O); if (typeof hint !== 'string' || (hint !== 'number' && hint !== 'string')) { throw new TypeError('hint must be "string" or "number"'); } var methodNames = hint === 'string' ? toStringOrder : toNumberOrder; var method; var result; for (var i = 0; i < orderLength; i += 1) { method = O[methodNames[i]]; if (isFunction(method)) { result = method.call(O); if (isPrimitive(result)) { return result; } } } throw new TypeError('No default value'); }; var getMethod = function _getMethod(O, P) { var func = O[P]; if (isNil(func) === false) { if (isFunction(func) === false) { throw new TypeError(func + ' returned for property ' + P + ' of object ' + O + ' is not a function'); } return func; } return void 0; }; // http://www.ecma-international.org/ecma-262/6.0/#sec-toprimitive /** * This method converts a JavaScript object to a primitive value. * Note: When toPrimitive is called with no hint, then it generally behaves as * if the hint were Number. However, objects may over-ride this behaviour by * defining a @@toPrimitive method. Of the objects defined in this specification * only Date objects (see 20.3.4.45) and Symbol objects (see 19.4.3.4) over-ride * the default ToPrimitive behaviour. Date objects treat no hint as if the hint * were String. * * @param {*} input - The input to convert. * @param {constructor} [prefferedtype] - The preffered type (String or Number). * @throws {TypeError} If unable to convert input to a primitive. * @returns {string|number} The converted input as a primitive. * @example * var toPrimitive = require('to-primitive-x'); * * var date = new Date(0); * toPrimitive(date)); // Thu Jan 01 1970 01:00:00 GMT+0100 (CET) * toPrimitive(date, String)); // Thu Jan 01 1970 01:00:00 GMT+0100 (CET) * toPrimitive(date, Number)); // 0 */ module.exports = function toPrimitive(input, preferredType) { if (isPrimitive(input)) { return input; } var hint = 'default'; if (arguments.length > 1) { if (preferredType === String) { hint = 'string'; } else if (preferredType === Number) { hint = 'number'; } } var exoticToPrim; if (hasSymbols) { if (symToPrimitive) { exoticToPrim = getMethod(input, symToPrimitive); } else if (isSymbol(input)) { exoticToPrim = symValueOf; } } if (isUndefined(exoticToPrim) === false) { var result = exoticToPrim.call(input, hint); if (isPrimitive(result)) { return result; } throw new TypeError('unable to convert exotic object to primitive'); } if (hint === 'default' && (isDate(input) || isSymbol(input))) { hint = 'string'; } return ordinaryToPrimitive(input, hint === 'default' ? 'number' : hint); };