Skip to content

Commit

Permalink
Adds change-array-by-copy polyfills
Browse files Browse the repository at this point in the history
Array.prototype.toReversed
Array.prototype.toSorted
Array.prototype.toSpliced
Array.prototype.with
%TypedArray%.prototype.toReversed
%TypedArray%.prototype.toSorted
%TypedArray%.prototype.with
  • Loading branch information
mhassan1 authored and JakeChampion committed May 3, 2023
1 parent 8778e11 commit b91e288
Show file tree
Hide file tree
Showing 34 changed files with 1,088 additions and 0 deletions.
30 changes: 30 additions & 0 deletions polyfills/Array/prototype/toReversed/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
aliases = [ "es2023" ]
dependencies = [
"_ESAbstract.ArrayCreate",
"_ESAbstract.CreateDataPropertyOrThrow",
"_ESAbstract.CreateMethodProperty",
"_ESAbstract.Get",
"_ESAbstract.LengthOfArrayLike",
"_ESAbstract.ToObject",
"_ESAbstract.ToString",
]
license = "MIT"
spec = "https://tc39.es/ecma262/#sec-array.prototype.toreversed"
docs = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toReversed"

[browsers]
android = "*"
bb = "*"
chrome = "<110"
edge = "*"
edge_mob = "*"
firefox = "*"
firefox_mob = "*"
ie = "*"
ie_mob = "*"
opera = "<96"
op_mob = "<74"
op_mini = "*"
safari = "<16.3"
ios_saf = "<16.3"
samsung_mob = "*"
1 change: 1 addition & 0 deletions polyfills/Array/prototype/toReversed/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
'toReversed' in Array.prototype
27 changes: 27 additions & 0 deletions polyfills/Array/prototype/toReversed/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* global ArrayCreate, CreateDataPropertyOrThrow, CreateMethodProperty, Get, LengthOfArrayLike, ToObject, ToString */
// 23.1.3.33 Array.prototype.toReversed ( )
CreateMethodProperty(Array.prototype, 'toReversed', function toReversed() {
// 1. Let O be ? ToObject(this value).
var O = ToObject(this);
// 2. Let len be ? LengthOfArrayLike(O).
var len = LengthOfArrayLike(O);
// 3. Let A be ? ArrayCreate(len).
var A = ArrayCreate(len);
// 4. Let k be 0.
var k = 0;
// 5. Repeat, while k < len,
while (k < len) {
// a. Let from be ! ToString(𝔽(len - k - 1)).
var from = ToString(len - k - 1);
// b. Let Pk be ! ToString(𝔽(k)).
var Pk = ToString(k);
// c. Let fromValue be ? Get(O, from).
var fromValue = Get(O, from);
// d. Perform ! CreateDataPropertyOrThrow(A, Pk, fromValue).
CreateDataPropertyOrThrow(A, Pk, fromValue);
// e. Set k to k + 1.
k = k + 1;
}
// 6. Return A.
return A;
});
34 changes: 34 additions & 0 deletions polyfills/Array/prototype/toReversed/tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* eslint-env mocha, browser */
/* global proclaim */

it('is a function', function () {
proclaim.isFunction(Array.prototype.toReversed);
});

it('has correct arity', function () {
proclaim.arity(Array.prototype.toReversed, 0);
});

it('has correct name', function () {
proclaim.hasName(Array.prototype.toReversed, 'toReversed');
});

it('is not enumerable', function () {
proclaim.isNotEnumerable(Array.prototype, 'toReversed');
});

describe('toReversed', function () {
[
{ kind: 'array', thing: [3, 4, 5, 6] },
{ kind: 'array-like object', thing: {0: 3, 1: 4, 2: 5, 3: 6, length: 4} }
].forEach(function (test) {
describe(test.kind, function () {
var thing = test.thing;

it('should reverse (by copy)', function () {
proclaim.deepStrictEqual(Array.prototype.toReversed.call(thing), [6, 5, 4, 3]);
proclaim.equal(thing[0], 3);
});
});
});
});
30 changes: 30 additions & 0 deletions polyfills/Array/prototype/toSorted/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
aliases = [ "es2023" ]
dependencies = [
"_ESAbstract.ArrayCreate",
"_ESAbstract.CreateDataPropertyOrThrow",
"_ESAbstract.CreateMethodProperty",
"_ESAbstract.IsCallable",
"_ESAbstract.LengthOfArrayLike",
"_ESAbstract.ToObject",
"_ESAbstract.ToString",
]
license = "MIT"
spec = "https://tc39.es/ecma262/#sec-array.prototype.tosorted"
docs = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted"

[browsers]
android = "*"
bb = "*"
chrome = "<110"
edge = "*"
edge_mob = "*"
firefox = "*"
firefox_mob = "*"
ie = "*"
ie_mob = "*"
opera = "<96"
op_mob = "<74"
op_mini = "*"
safari = "<16.3"
ios_saf = "<16.3"
samsung_mob = "*"
1 change: 1 addition & 0 deletions polyfills/Array/prototype/toSorted/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
'toSorted' in Array.prototype
35 changes: 35 additions & 0 deletions polyfills/Array/prototype/toSorted/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* global ArrayCreate, CreateDataPropertyOrThrow, CreateMethodProperty, IsCallable, LengthOfArrayLike, ToObject, ToString */
// 23.1.3.34 Array.prototype.toSorted ( comparefn )
CreateMethodProperty(Array.prototype, 'toSorted', function toSorted(comparefn) {
// 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
if (comparefn !== undefined && IsCallable(comparefn) === false) {
throw new TypeError(
"The comparison function must be either a function or undefined"
);
}
// 2. Let O be ? ToObject(this value).
var O = ToObject(this);
// 3. Let len be ? LengthOfArrayLike(O).
var len = LengthOfArrayLike(O);
// 4. Let A be ? ArrayCreate(len).
var A = ArrayCreate(len);

// 7. Let j be 0.
var j = 0;
// 8. Repeat, while j < len,
while (j < len) {
// a. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(j)), sortedList[j]).
CreateDataPropertyOrThrow(A, ToString(j), O[j]);
// b. Set j to j + 1.
j = j + 1;
}

// Polyfill.io - These steps are handled by native `Array.prototype.sort`, below
// 5. Let SortCompare be a new Abstract Closure with parameters (x, y) that captures comparefn and performs the following steps when called:
// a. Return ? CompareArrayElements(x, y, comparefn).
// 6. Let sortedList be ? SortIndexedProperties(O, len, SortCompare, read-through-holes).
A.sort(comparefn);

// 9. Return A.
return A;
});
48 changes: 48 additions & 0 deletions polyfills/Array/prototype/toSorted/tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* eslint-env mocha, browser */
/* global proclaim */

it('is a function', function () {
proclaim.isFunction(Array.prototype.toSorted);
});

it('has correct arity', function () {
proclaim.arity(Array.prototype.toSorted, 1);
});

it('has correct name', function () {
proclaim.hasName(Array.prototype.toSorted, 'toSorted');
});

it('is not enumerable', function () {
proclaim.isNotEnumerable(Array.prototype, 'toSorted');
});

describe('toSorted', function () {
[
// eslint-disable-next-line no-sparse-arrays
{ kind: 'array', thing: [6, 4, 5, , 3] },
{ kind: 'array-like object', thing: {0: 6, 1: 4, 2: 5, 4: 3, length: 5} }
].forEach(function (test) {
describe(test.kind, function () {
var thing = test.thing;

it('should sort with no comparefn (by copy)', function () {
proclaim.deepStrictEqual(Array.prototype.toSorted.call(thing), [3, 4, 5, 6, undefined]);
proclaim.equal(thing[0], 6);
});

it('should sort with comparefn (by copy)', function () {
proclaim.deepStrictEqual(Array.prototype.toSorted.call(thing, function (a, b) {
return a - b;
}), [3, 4, 5, 6, undefined]);
proclaim.equal(thing[0], 6);
});

it('should throw for invalid comparefn', function () {
proclaim.throws(function () {
Array.prototype.toSorted.call(thing, 'invalid');
});
});
});
});
});
32 changes: 32 additions & 0 deletions polyfills/Array/prototype/toSpliced/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
aliases = [ "es2023" ]
dependencies = [
"_ESAbstract.ArrayCreate",
"_ESAbstract.CreateDataPropertyOrThrow",
"_ESAbstract.CreateMethodProperty",
"_ESAbstract.Get",
"_ESAbstract.LengthOfArrayLike",
"_ESAbstract.ToIntegerOrInfinity",
"_ESAbstract.ToObject",
"_ESAbstract.ToString",
"Number.MAX_SAFE_INTEGER",
]
license = "MIT"
spec = "https://tc39.es/ecma262/#sec-array.prototype.tospliced"
docs = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSpliced"

[browsers]
android = "*"
bb = "*"
chrome = "<110"
edge = "*"
edge_mob = "*"
firefox = "*"
firefox_mob = "*"
ie = "*"
ie_mob = "*"
opera = "<96"
op_mob = "<74"
op_mini = "*"
safari = "<16.3"
ios_saf = "<16.3"
samsung_mob = "*"
1 change: 1 addition & 0 deletions polyfills/Array/prototype/toSpliced/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
'toSpliced' in Array.prototype
94 changes: 94 additions & 0 deletions polyfills/Array/prototype/toSpliced/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* global ArrayCreate, CreateDataPropertyOrThrow, CreateMethodProperty, Get, LengthOfArrayLike, ToIntegerOrInfinity, ToObject, ToString */
// 23.1.3.35 Array.prototype.toSpliced ( start, skipCount, ...items )
CreateMethodProperty(Array.prototype, 'toSpliced', function toSpliced(start, skipCount) {
// 1. Let O be ? ToObject(this value).
var O = ToObject(this);
// 2. Let len be ? LengthOfArrayLike(O).
var len = LengthOfArrayLike(O);
// 3. Let relativeStart be ? ToIntegerOrInfinity(start).
var relativeStart = ToIntegerOrInfinity(start);

var actualStart;
// 4. If relativeStart is -∞, let actualStart be 0.
if (relativeStart === -Infinity) {
actualStart = 0
}
// 5. Else if relativeStart < 0, let actualStart be max(len + relativeStart, 0).
else if (relativeStart < 0) {
actualStart = Math.max(len + relativeStart, 0);
}
// 6. Else, let actualStart be min(relativeStart, len).
else {
actualStart = Math.min(relativeStart, len);
}

// 7. Let insertCount be the number of elements in items.
var items = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : [];
var insertCount = items.length;

var actualSkipCount;
// 8. If start is not present, then
if (arguments.length === 0) {
// a. Let actualSkipCount be 0.
actualSkipCount = 0;
}
// 9. Else if skipCount is not present, then
else if (arguments.length === 1) {
// a. Let actualSkipCount be len - actualStart.
actualSkipCount = len - actualStart;
}
// 10. Else,
else {
// a. Let sc be ? ToIntegerOrInfinity(skipCount).
var sc = ToIntegerOrInfinity(skipCount);
// b. Let actualSkipCount be the result of clamping sc between 0 and len - actualStart.
actualSkipCount = Math.min(Math.max(0, sc), len - actualStart);
}

// 11. Let newLen be len + insertCount - actualSkipCount.
var newLen = len + insertCount - actualSkipCount;
// 12. If newLen > 253 - 1, throw a TypeError exception.
if (newLen > Number.MAX_SAFE_INTEGER) {
throw new TypeError('Length exceeded the maximum array length');
}
// 13. Let A be ? ArrayCreate(newLen).
var A = ArrayCreate(newLen);
// 14. Let i be 0.
var i = 0;
// 15. Let r be actualStart + actualSkipCount.
var r = actualStart + actualSkipCount;
// 16. Repeat, while i < actualStart,
while (i < actualStart) {
// a. Let Pi be ! ToString(𝔽(i)).
var Pi = ToString(i);
// b. Let iValue be ? Get(O, Pi).
var iValue = Get(O, Pi);
// c. Perform ! CreateDataPropertyOrThrow(A, Pi, iValue).
CreateDataPropertyOrThrow(A, Pi, iValue);
// d. Set i to i + 1.
i = i + 1;
}
// 17. For each element E of items, do
items.forEach(function (E) {
var Pi = ToString(i);
CreateDataPropertyOrThrow(A, Pi, E);
i = i + 1;
});
// 18. Repeat, while i < newLen,
while (i < newLen) {
// a. Let Pi be ! ToString(𝔽(i)).
var Pi2 = ToString(i);
// b. Let from be ! ToString(𝔽(r)).
var from = ToString(r);
// c. Let fromValue be ? Get(O, from).
var fromValue = Get(O, from);
// d. Perform ! CreateDataPropertyOrThrow(A, Pi, fromValue).
CreateDataPropertyOrThrow(A, Pi2, fromValue);
// e. Set i to i + 1.
i = i + 1;
// f. Set r to r + 1.
r = r + 1;
}
// 19. Return A.
return A;
});
55 changes: 55 additions & 0 deletions polyfills/Array/prototype/toSpliced/tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/* eslint-env mocha, browser */
/* global proclaim */

it('is a function', function () {
proclaim.isFunction(Array.prototype.toSpliced);
});

it('has correct arity', function () {
proclaim.arity(Array.prototype.toSpliced, 2);
});

it('has correct name', function () {
proclaim.hasName(Array.prototype.toSpliced, 'toSpliced');
});

it('is not enumerable', function () {
proclaim.isNotEnumerable(Array.prototype, 'toSpliced');
});

describe('toSpliced', function () {
[
// eslint-disable-next-line no-sparse-arrays
{ kind: 'array', thing: [3, 4, 5, 6] },
{ kind: 'array-like object', thing: {0: 3, 1: 4, 2: 5, 3: 6, length: 4} }
].forEach(function (test) {
describe(test.kind, function () {
var thing = test.thing;

it('should splice with no start (by copy)', function () {
proclaim.deepStrictEqual(Array.prototype.toSpliced.call(thing), [3, 4, 5, 6]);
proclaim.equal(thing[0], 3);
});

it('should splice with no skipCount (by copy)', function () {
proclaim.deepStrictEqual(Array.prototype.toSpliced.call(thing, 0), []);
proclaim.equal(thing[0], 3);
});

it('should splice with no items (by copy)', function () {
proclaim.deepStrictEqual(Array.prototype.toSpliced.call(thing, 0, 1), [4, 5, 6]);
proclaim.equal(thing[0], 3);
});

it('should splice with items (by copy)', function () {
proclaim.deepStrictEqual(Array.prototype.toSpliced.call(thing, 0, 1, 1, 2), [1, 2, 4, 5, 6]);
proclaim.equal(thing[0], 3);
});

it('should splice with items and negative start (by copy)', function () {
proclaim.deepStrictEqual(Array.prototype.toSpliced.call(thing, -4, 1, 1, 2), [1, 2, 4, 5, 6]);
proclaim.equal(thing[0], 3);
});
});
});
});

0 comments on commit b91e288

Please sign in to comment.