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