123 lines
3.6 KiB
JavaScript
123 lines
3.6 KiB
JavaScript
/**
|
|
* @file Converts a JavaScript object to a primitive value.
|
|
* @version 1.1.0
|
|
* @author Xotic750 <Xotic750@gmail.com>
|
|
* @copyright Xotic750
|
|
* @license {@link <https://opensource.org/licenses/MIT> 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);
|
|
};
|