es5.js 6.3 KB

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