ArraySetLength.js 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. 'use strict';
  2. var GetIntrinsic = require('get-intrinsic');
  3. var $RangeError = GetIntrinsic('%RangeError%');
  4. var $TypeError = GetIntrinsic('%TypeError%');
  5. var assign = require('object.assign');
  6. var isPropertyDescriptor = require('../helpers/isPropertyDescriptor');
  7. var IsArray = require('./IsArray');
  8. var IsAccessorDescriptor = require('./IsAccessorDescriptor');
  9. var IsDataDescriptor = require('./IsDataDescriptor');
  10. var OrdinaryDefineOwnProperty = require('./OrdinaryDefineOwnProperty');
  11. var OrdinaryGetOwnProperty = require('./OrdinaryGetOwnProperty');
  12. var ToNumber = require('./ToNumber');
  13. var ToString = require('./ToString');
  14. var ToUint32 = require('./ToUint32');
  15. var Type = require('./Type');
  16. // https://ecma-international.org/ecma-262/6.0/#sec-arraysetlength
  17. // eslint-disable-next-line max-statements, max-lines-per-function
  18. module.exports = function ArraySetLength(A, Desc) {
  19. if (!IsArray(A)) {
  20. throw new $TypeError('Assertion failed: A must be an Array');
  21. }
  22. if (!isPropertyDescriptor({
  23. Type: Type,
  24. IsDataDescriptor: IsDataDescriptor,
  25. IsAccessorDescriptor: IsAccessorDescriptor
  26. }, Desc)) {
  27. throw new $TypeError('Assertion failed: Desc must be a Property Descriptor');
  28. }
  29. if (!('[[Value]]' in Desc)) {
  30. return OrdinaryDefineOwnProperty(A, 'length', Desc);
  31. }
  32. var newLenDesc = assign({}, Desc);
  33. var newLen = ToUint32(Desc['[[Value]]']);
  34. var numberLen = ToNumber(Desc['[[Value]]']);
  35. if (newLen !== numberLen) {
  36. throw new $RangeError('Invalid array length');
  37. }
  38. newLenDesc['[[Value]]'] = newLen;
  39. var oldLenDesc = OrdinaryGetOwnProperty(A, 'length');
  40. if (!IsDataDescriptor(oldLenDesc)) {
  41. throw new $TypeError('Assertion failed: an array had a non-data descriptor on `length`');
  42. }
  43. var oldLen = oldLenDesc['[[Value]]'];
  44. if (newLen >= oldLen) {
  45. return OrdinaryDefineOwnProperty(A, 'length', newLenDesc);
  46. }
  47. if (!oldLenDesc['[[Writable]]']) {
  48. return false;
  49. }
  50. var newWritable;
  51. if (!('[[Writable]]' in newLenDesc) || newLenDesc['[[Writable]]']) {
  52. newWritable = true;
  53. } else {
  54. newWritable = false;
  55. newLenDesc['[[Writable]]'] = true;
  56. }
  57. var succeeded = OrdinaryDefineOwnProperty(A, 'length', newLenDesc);
  58. if (!succeeded) {
  59. return false;
  60. }
  61. while (newLen < oldLen) {
  62. oldLen -= 1;
  63. // eslint-disable-next-line no-param-reassign
  64. var deleteSucceeded = delete A[ToString(oldLen)];
  65. if (!deleteSucceeded) {
  66. newLenDesc['[[Value]]'] = oldLen + 1;
  67. if (!newWritable) {
  68. newLenDesc['[[Writable]]'] = false;
  69. OrdinaryDefineOwnProperty(A, 'length', newLenDesc);
  70. return false;
  71. }
  72. }
  73. }
  74. if (!newWritable) {
  75. return OrdinaryDefineOwnProperty(A, 'length', { '[[Writable]]': false });
  76. }
  77. return true;
  78. };