ArraySetLength.js 2.4 KB

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