es5.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. 'use strict';
  2. var GetIntrinsic = require('./GetIntrinsic');
  3. var $Object = GetIntrinsic('%Object%');
  4. var $TypeError = GetIntrinsic('%TypeError%');
  5. var $String = GetIntrinsic('%String%');
  6. var assertRecord = require('./helpers/assertRecord');
  7. var $isNaN = require('./helpers/isNaN');
  8. var $isFinite = require('./helpers/isFinite');
  9. var sign = require('./helpers/sign');
  10. var mod = require('./helpers/mod');
  11. var IsCallable = require('is-callable');
  12. var toPrimitive = require('es-to-primitive/es5');
  13. var has = require('has');
  14. // https://es5.github.io/#x9
  15. var ES5 = {
  16. ToPrimitive: toPrimitive,
  17. ToBoolean: function ToBoolean(value) {
  18. return !!value;
  19. },
  20. ToNumber: function ToNumber(value) {
  21. return +value; // eslint-disable-line no-implicit-coercion
  22. },
  23. ToInteger: function ToInteger(value) {
  24. var number = this.ToNumber(value);
  25. if ($isNaN(number)) { return 0; }
  26. if (number === 0 || !$isFinite(number)) { return number; }
  27. return sign(number) * Math.floor(Math.abs(number));
  28. },
  29. ToInt32: function ToInt32(x) {
  30. return this.ToNumber(x) >> 0;
  31. },
  32. ToUint32: function ToUint32(x) {
  33. return this.ToNumber(x) >>> 0;
  34. },
  35. ToUint16: function ToUint16(value) {
  36. var number = this.ToNumber(value);
  37. if ($isNaN(number) || number === 0 || !$isFinite(number)) { return 0; }
  38. var posInt = sign(number) * Math.floor(Math.abs(number));
  39. return mod(posInt, 0x10000);
  40. },
  41. ToString: function ToString(value) {
  42. return $String(value);
  43. },
  44. ToObject: function ToObject(value) {
  45. this.CheckObjectCoercible(value);
  46. return $Object(value);
  47. },
  48. CheckObjectCoercible: function CheckObjectCoercible(value, optMessage) {
  49. /* jshint eqnull:true */
  50. if (value == null) {
  51. throw new $TypeError(optMessage || 'Cannot call method on ' + value);
  52. }
  53. return value;
  54. },
  55. IsCallable: IsCallable,
  56. SameValue: function SameValue(x, y) {
  57. if (x === y) { // 0 === -0, but they are not identical.
  58. if (x === 0) { return 1 / x === 1 / y; }
  59. return true;
  60. }
  61. return $isNaN(x) && $isNaN(y);
  62. },
  63. // https://www.ecma-international.org/ecma-262/5.1/#sec-8
  64. Type: function Type(x) {
  65. if (x === null) {
  66. return 'Null';
  67. }
  68. if (typeof x === 'undefined') {
  69. return 'Undefined';
  70. }
  71. if (typeof x === 'function' || typeof x === 'object') {
  72. return 'Object';
  73. }
  74. if (typeof x === 'number') {
  75. return 'Number';
  76. }
  77. if (typeof x === 'boolean') {
  78. return 'Boolean';
  79. }
  80. if (typeof x === 'string') {
  81. return 'String';
  82. }
  83. },
  84. // https://ecma-international.org/ecma-262/6.0/#sec-property-descriptor-specification-type
  85. IsPropertyDescriptor: function IsPropertyDescriptor(Desc) {
  86. if (this.Type(Desc) !== 'Object') {
  87. return false;
  88. }
  89. var allowed = {
  90. '[[Configurable]]': true,
  91. '[[Enumerable]]': true,
  92. '[[Get]]': true,
  93. '[[Set]]': true,
  94. '[[Value]]': true,
  95. '[[Writable]]': true
  96. };
  97. for (var key in Desc) { // eslint-disable-line
  98. if (has(Desc, key) && !allowed[key]) {
  99. return false;
  100. }
  101. }
  102. var isData = has(Desc, '[[Value]]');
  103. var IsAccessor = has(Desc, '[[Get]]') || has(Desc, '[[Set]]');
  104. if (isData && IsAccessor) {
  105. throw new $TypeError('Property Descriptors may not be both accessor and data descriptors');
  106. }
  107. return true;
  108. },
  109. // https://ecma-international.org/ecma-262/5.1/#sec-8.10.1
  110. IsAccessorDescriptor: function IsAccessorDescriptor(Desc) {
  111. if (typeof Desc === 'undefined') {
  112. return false;
  113. }
  114. assertRecord(this, 'Property Descriptor', 'Desc', Desc);
  115. if (!has(Desc, '[[Get]]') && !has(Desc, '[[Set]]')) {
  116. return false;
  117. }
  118. return true;
  119. },
  120. // https://ecma-international.org/ecma-262/5.1/#sec-8.10.2
  121. IsDataDescriptor: function IsDataDescriptor(Desc) {
  122. if (typeof Desc === 'undefined') {
  123. return false;
  124. }
  125. assertRecord(this, 'Property Descriptor', 'Desc', Desc);
  126. if (!has(Desc, '[[Value]]') && !has(Desc, '[[Writable]]')) {
  127. return false;
  128. }
  129. return true;
  130. },
  131. // https://ecma-international.org/ecma-262/5.1/#sec-8.10.3
  132. IsGenericDescriptor: function IsGenericDescriptor(Desc) {
  133. if (typeof Desc === 'undefined') {
  134. return false;
  135. }
  136. assertRecord(this, 'Property Descriptor', 'Desc', Desc);
  137. if (!this.IsAccessorDescriptor(Desc) && !this.IsDataDescriptor(Desc)) {
  138. return true;
  139. }
  140. return false;
  141. },
  142. // https://ecma-international.org/ecma-262/5.1/#sec-8.10.4
  143. FromPropertyDescriptor: function FromPropertyDescriptor(Desc) {
  144. if (typeof Desc === 'undefined') {
  145. return Desc;
  146. }
  147. assertRecord(this, 'Property Descriptor', 'Desc', Desc);
  148. if (this.IsDataDescriptor(Desc)) {
  149. return {
  150. value: Desc['[[Value]]'],
  151. writable: !!Desc['[[Writable]]'],
  152. enumerable: !!Desc['[[Enumerable]]'],
  153. configurable: !!Desc['[[Configurable]]']
  154. };
  155. } else if (this.IsAccessorDescriptor(Desc)) {
  156. return {
  157. get: Desc['[[Get]]'],
  158. set: Desc['[[Set]]'],
  159. enumerable: !!Desc['[[Enumerable]]'],
  160. configurable: !!Desc['[[Configurable]]']
  161. };
  162. } else {
  163. throw new $TypeError('FromPropertyDescriptor must be called with a fully populated Property Descriptor');
  164. }
  165. },
  166. // https://ecma-international.org/ecma-262/5.1/#sec-8.10.5
  167. ToPropertyDescriptor: function ToPropertyDescriptor(Obj) {
  168. if (this.Type(Obj) !== 'Object') {
  169. throw new $TypeError('ToPropertyDescriptor requires an object');
  170. }
  171. var desc = {};
  172. if (has(Obj, 'enumerable')) {
  173. desc['[[Enumerable]]'] = this.ToBoolean(Obj.enumerable);
  174. }
  175. if (has(Obj, 'configurable')) {
  176. desc['[[Configurable]]'] = this.ToBoolean(Obj.configurable);
  177. }
  178. if (has(Obj, 'value')) {
  179. desc['[[Value]]'] = Obj.value;
  180. }
  181. if (has(Obj, 'writable')) {
  182. desc['[[Writable]]'] = this.ToBoolean(Obj.writable);
  183. }
  184. if (has(Obj, 'get')) {
  185. var getter = Obj.get;
  186. if (typeof getter !== 'undefined' && !this.IsCallable(getter)) {
  187. throw new TypeError('getter must be a function');
  188. }
  189. desc['[[Get]]'] = getter;
  190. }
  191. if (has(Obj, 'set')) {
  192. var setter = Obj.set;
  193. if (typeof setter !== 'undefined' && !this.IsCallable(setter)) {
  194. throw new $TypeError('setter must be a function');
  195. }
  196. desc['[[Set]]'] = setter;
  197. }
  198. if ((has(desc, '[[Get]]') || has(desc, '[[Set]]')) && (has(desc, '[[Value]]') || has(desc, '[[Writable]]'))) {
  199. throw new $TypeError('Invalid property descriptor. Cannot both specify accessors and a value or writable attribute');
  200. }
  201. return desc;
  202. }
  203. };
  204. module.exports = ES5;