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