| 'use strict'; |
| |
| var GetIntrinsic = require('./GetIntrinsic'); |
| |
| var $Object = GetIntrinsic('%Object%'); |
| var $TypeError = GetIntrinsic('%TypeError%'); |
| var $String = GetIntrinsic('%String%'); |
| |
| var assertRecord = require('./helpers/assertRecord'); |
| var $isNaN = require('./helpers/isNaN'); |
| var $isFinite = require('./helpers/isFinite'); |
| |
| var sign = require('./helpers/sign'); |
| var mod = require('./helpers/mod'); |
| |
| var IsCallable = require('is-callable'); |
| var toPrimitive = require('es-to-primitive/es5'); |
| |
| var has = require('has'); |
| |
| // https://es5.github.io/#x9 |
| var ES5 = { |
| ToPrimitive: toPrimitive, |
| |
| ToBoolean: function ToBoolean(value) { |
| return !!value; |
| }, |
| ToNumber: function ToNumber(value) { |
| return +value; // eslint-disable-line no-implicit-coercion |
| }, |
| ToInteger: function ToInteger(value) { |
| var number = this.ToNumber(value); |
| if ($isNaN(number)) { return 0; } |
| if (number === 0 || !$isFinite(number)) { return number; } |
| return sign(number) * Math.floor(Math.abs(number)); |
| }, |
| ToInt32: function ToInt32(x) { |
| return this.ToNumber(x) >> 0; |
| }, |
| ToUint32: function ToUint32(x) { |
| return this.ToNumber(x) >>> 0; |
| }, |
| ToUint16: function ToUint16(value) { |
| var number = this.ToNumber(value); |
| if ($isNaN(number) || number === 0 || !$isFinite(number)) { return 0; } |
| var posInt = sign(number) * Math.floor(Math.abs(number)); |
| return mod(posInt, 0x10000); |
| }, |
| ToString: function ToString(value) { |
| return $String(value); |
| }, |
| ToObject: function ToObject(value) { |
| this.CheckObjectCoercible(value); |
| return $Object(value); |
| }, |
| CheckObjectCoercible: function CheckObjectCoercible(value, optMessage) { |
| /* jshint eqnull:true */ |
| if (value == null) { |
| throw new $TypeError(optMessage || 'Cannot call method on ' + value); |
| } |
| return value; |
| }, |
| IsCallable: IsCallable, |
| SameValue: function SameValue(x, y) { |
| if (x === y) { // 0 === -0, but they are not identical. |
| if (x === 0) { return 1 / x === 1 / y; } |
| return true; |
| } |
| return $isNaN(x) && $isNaN(y); |
| }, |
| |
| // https://www.ecma-international.org/ecma-262/5.1/#sec-8 |
| Type: function Type(x) { |
| if (x === null) { |
| return 'Null'; |
| } |
| if (typeof x === 'undefined') { |
| return 'Undefined'; |
| } |
| if (typeof x === 'function' || typeof x === 'object') { |
| return 'Object'; |
| } |
| if (typeof x === 'number') { |
| return 'Number'; |
| } |
| if (typeof x === 'boolean') { |
| return 'Boolean'; |
| } |
| if (typeof x === 'string') { |
| return 'String'; |
| } |
| }, |
| |
| // https://ecma-international.org/ecma-262/6.0/#sec-property-descriptor-specification-type |
| IsPropertyDescriptor: function IsPropertyDescriptor(Desc) { |
| if (this.Type(Desc) !== 'Object') { |
| return false; |
| } |
| var allowed = { |
| '[[Configurable]]': true, |
| '[[Enumerable]]': true, |
| '[[Get]]': true, |
| '[[Set]]': true, |
| '[[Value]]': true, |
| '[[Writable]]': true |
| }; |
| |
| for (var key in Desc) { // eslint-disable-line |
| if (has(Desc, key) && !allowed[key]) { |
| return false; |
| } |
| } |
| |
| var isData = has(Desc, '[[Value]]'); |
| var IsAccessor = has(Desc, '[[Get]]') || has(Desc, '[[Set]]'); |
| if (isData && IsAccessor) { |
| throw new $TypeError('Property Descriptors may not be both accessor and data descriptors'); |
| } |
| return true; |
| }, |
| |
| // https://ecma-international.org/ecma-262/5.1/#sec-8.10.1 |
| IsAccessorDescriptor: function IsAccessorDescriptor(Desc) { |
| if (typeof Desc === 'undefined') { |
| return false; |
| } |
| |
| assertRecord(this, 'Property Descriptor', 'Desc', Desc); |
| |
| if (!has(Desc, '[[Get]]') && !has(Desc, '[[Set]]')) { |
| return false; |
| } |
| |
| return true; |
| }, |
| |
| // https://ecma-international.org/ecma-262/5.1/#sec-8.10.2 |
| IsDataDescriptor: function IsDataDescriptor(Desc) { |
| if (typeof Desc === 'undefined') { |
| return false; |
| } |
| |
| assertRecord(this, 'Property Descriptor', 'Desc', Desc); |
| |
| if (!has(Desc, '[[Value]]') && !has(Desc, '[[Writable]]')) { |
| return false; |
| } |
| |
| return true; |
| }, |
| |
| // https://ecma-international.org/ecma-262/5.1/#sec-8.10.3 |
| IsGenericDescriptor: function IsGenericDescriptor(Desc) { |
| if (typeof Desc === 'undefined') { |
| return false; |
| } |
| |
| assertRecord(this, 'Property Descriptor', 'Desc', Desc); |
| |
| if (!this.IsAccessorDescriptor(Desc) && !this.IsDataDescriptor(Desc)) { |
| return true; |
| } |
| |
| return false; |
| }, |
| |
| // https://ecma-international.org/ecma-262/5.1/#sec-8.10.4 |
| FromPropertyDescriptor: function FromPropertyDescriptor(Desc) { |
| if (typeof Desc === 'undefined') { |
| return Desc; |
| } |
| |
| assertRecord(this, 'Property Descriptor', 'Desc', Desc); |
| |
| if (this.IsDataDescriptor(Desc)) { |
| return { |
| value: Desc['[[Value]]'], |
| writable: !!Desc['[[Writable]]'], |
| enumerable: !!Desc['[[Enumerable]]'], |
| configurable: !!Desc['[[Configurable]]'] |
| }; |
| } else if (this.IsAccessorDescriptor(Desc)) { |
| return { |
| get: Desc['[[Get]]'], |
| set: Desc['[[Set]]'], |
| enumerable: !!Desc['[[Enumerable]]'], |
| configurable: !!Desc['[[Configurable]]'] |
| }; |
| } else { |
| throw new $TypeError('FromPropertyDescriptor must be called with a fully populated Property Descriptor'); |
| } |
| }, |
| |
| // https://ecma-international.org/ecma-262/5.1/#sec-8.10.5 |
| ToPropertyDescriptor: function ToPropertyDescriptor(Obj) { |
| if (this.Type(Obj) !== 'Object') { |
| throw new $TypeError('ToPropertyDescriptor requires an object'); |
| } |
| |
| var desc = {}; |
| if (has(Obj, 'enumerable')) { |
| desc['[[Enumerable]]'] = this.ToBoolean(Obj.enumerable); |
| } |
| if (has(Obj, 'configurable')) { |
| desc['[[Configurable]]'] = this.ToBoolean(Obj.configurable); |
| } |
| if (has(Obj, 'value')) { |
| desc['[[Value]]'] = Obj.value; |
| } |
| if (has(Obj, 'writable')) { |
| desc['[[Writable]]'] = this.ToBoolean(Obj.writable); |
| } |
| if (has(Obj, 'get')) { |
| var getter = Obj.get; |
| if (typeof getter !== 'undefined' && !this.IsCallable(getter)) { |
| throw new TypeError('getter must be a function'); |
| } |
| desc['[[Get]]'] = getter; |
| } |
| if (has(Obj, 'set')) { |
| var setter = Obj.set; |
| if (typeof setter !== 'undefined' && !this.IsCallable(setter)) { |
| throw new $TypeError('setter must be a function'); |
| } |
| desc['[[Set]]'] = setter; |
| } |
| |
| if ((has(desc, '[[Get]]') || has(desc, '[[Set]]')) && (has(desc, '[[Value]]') || has(desc, '[[Writable]]'))) { |
| throw new $TypeError('Invalid property descriptor. Cannot both specify accessors and a value or writable attribute'); |
| } |
| return desc; |
| } |
| }; |
| |
| module.exports = ES5; |