Skip to content

Commit

Permalink
Adds Array.prototype.at, String.prototype.at, and `TypedArray.pro…
Browse files Browse the repository at this point in the history
…totype.at` polyfills
  • Loading branch information
mhassan1 authored and JakeChampion committed Nov 18, 2021
1 parent 21967a1 commit 29c6814
Show file tree
Hide file tree
Showing 16 changed files with 374 additions and 0 deletions.
29 changes: 29 additions & 0 deletions polyfills/Array/prototype/at/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
aliases = [ "es2022" ]
dependencies = [
"_ESAbstract.CreateMethodProperty",
"_ESAbstract.Get",
"_ESAbstract.LengthOfArrayLike",
"_ESAbstract.ToIntegerOrInfinity",
"_ESAbstract.ToObject",
"_ESAbstract.ToString",
]
spec = "https://tc39.es/ecma262/#sec-array.prototype.at"
docs = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at"

[browsers]
android = "*"
bb = "*"
chrome = "< 92"
edge = "*"
edge_mob = "*"
firefox = "< 90"
firefox_mob = "< 90"
ie = "*"
ie_mob = "*"
ios_chr = "*"
ios_saf = "*"
op_mini = "*"
op_mob = "*"
opera = "< 78"
safari = "*"
samsung_mob = "< 16"
1 change: 1 addition & 0 deletions polyfills/Array/prototype/at/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
'at' in Array.prototype
19 changes: 19 additions & 0 deletions polyfills/Array/prototype/at/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* global CreateMethodProperty, Get, LengthOfArrayLike, ToIntegerOrInfinity, ToObject, ToString */
// 23.1.3.1. Array.prototype.at ( index )
CreateMethodProperty(Array.prototype, 'at', function at(index) {
// 1. Let O be ? ToObject(this value).
var O = ToObject(this);
// 2. Let len be ? LengthOfArrayLike(O).
var len = LengthOfArrayLike(O);
// 3. Let relativeIndex be ? ToIntegerOrInfinity(index).
var relativeIndex = ToIntegerOrInfinity(index);
// 4. If relativeIndex ≥ 0, then
// 4.a. Let k be relativeIndex.
// 5. Else,
// 5.a. Let k be len + relativeIndex.
var k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex;
// 6. If k < 0 or k ≥ len, return undefined.
if (k < 0 || k >= len) return undefined;
// 7. Return ? Get(O, ! ToString(𝔽(k))).
return Get(O, ToString(k));
});
44 changes: 44 additions & 0 deletions polyfills/Array/prototype/at/tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* eslint-env mocha, browser */
/* global proclaim */

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

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

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

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

describe('at', function () {
it('retrieves values by index for arrays', function () {
var array = ['a', 'b', 'c'];
proclaim.equal(array.at(undefined), 'a');
proclaim.equal(array.at(-4), undefined);
proclaim.equal(array.at(-2), 'b');
proclaim.equal(array.at(-0.5), 'a');
proclaim.equal(array.at(0), 'a');
proclaim.equal(array.at(0.5), 'a');
proclaim.equal(array.at(2), 'c');
proclaim.equal(array.at(4), undefined);
});

it('retrieves values by index for array-like objects', function () {
var object = { 0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 3 };
proclaim.equal(Array.prototype.at.call(object, undefined), 'a');
proclaim.equal(Array.prototype.at.call(object, -4), undefined);
proclaim.equal(Array.prototype.at.call(object, -2), 'b');
proclaim.equal(Array.prototype.at.call(object, -0.5), 'a');
proclaim.equal(Array.prototype.at.call(object, 0), 'a');
proclaim.equal(Array.prototype.at.call(object, 0.5), 'a');
proclaim.equal(Array.prototype.at.call(object, 2), 'c');
proclaim.equal(Array.prototype.at.call(object, 4), undefined);
});
});
27 changes: 27 additions & 0 deletions polyfills/String/prototype/at/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
aliases = [ "es2022" ]
dependencies = [
"_ESAbstract.CreateMethodProperty",
"_ESAbstract.RequireObjectCoercible",
"_ESAbstract.ToIntegerOrInfinity",
"_ESAbstract.ToString",
]
spec = "https://tc39.es/ecma262/#sec-string.prototype.at"
docs = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/at"

[browsers]
android = "*"
bb = "*"
chrome = "< 92"
edge = "*"
edge_mob = "*"
firefox = "< 90"
firefox_mob = "< 90"
ie = "*"
ie_mob = "*"
ios_chr = "*"
ios_saf = "*"
op_mini = "*"
op_mob = "*"
opera = "< 78"
safari = "*"
samsung_mob = "< 16"
1 change: 1 addition & 0 deletions polyfills/String/prototype/at/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
'at' in String.prototype
21 changes: 21 additions & 0 deletions polyfills/String/prototype/at/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* global CreateMethodProperty, RequireObjectCoercible, ToIntegerOrInfinity, ToString */
// 22.1.3.1. String.prototype.at ( index )
CreateMethodProperty(String.prototype, 'at', function at(index) {
// 1. Let O be ? RequireObjectCoercible(this value).
var O = RequireObjectCoercible(this);
// 2. Let S be ? ToString(O).
var S = ToString(O);
// 3. Let len be the length of S.
var len = S.length;
// 4. Let relativeIndex be ? ToIntegerOrInfinity(index).
var relativeIndex = ToIntegerOrInfinity(index);
// 5. If relativeIndex ≥ 0, then
// 5.a. Let k be relativeIndex.
// 6. Else,
// 6.a. Let k be len + relativeIndex.
var k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex;
// 7. If k < 0 or k ≥ len, return undefined.
if (k < 0 || k >= len) return undefined;
// 8. Return the substring of S from k to k + 1.
return S.substring(k, k + 1);
});
32 changes: 32 additions & 0 deletions polyfills/String/prototype/at/tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-env mocha, browser */
/* global proclaim */

it('is a function', function () {
proclaim.isFunction(String.prototype.at);
});

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

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

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

describe('at', function () {
it('retrieves values by index for strings', function () {
var string = 'abc';
proclaim.equal(string.at(undefined), 'a');
proclaim.equal(string.at(-4), undefined);
proclaim.equal(string.at(-2), 'b');
proclaim.equal(string.at(-0.5), 'a');
proclaim.equal(string.at(0), 'a');
proclaim.equal(string.at(0.5), 'a');
proclaim.equal(string.at(2), 'c');
proclaim.equal(string.at(4), undefined);
});
});
28 changes: 28 additions & 0 deletions polyfills/TypedArray/prototype/at/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
aliases = [ "es2022" ]
dependencies = [
"_ESAbstract.CreateMethodProperty",
"_ESAbstract.Get",
"_ESAbstract.ToIntegerOrInfinity",
"_ESAbstract.ToString",
"ArrayBuffer",
]
spec = "https://tc39.es/ecma262/#sec-%typedarray%.prototype.at"
docs = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/at"

[browsers]
android = "*"
bb = "*"
chrome = "< 92"
edge = "*"
edge_mob = "*"
firefox = "< 90"
firefox_mob = "< 90"
ie = "*"
ie_mob = "*"
ios_chr = "*"
ios_saf = "*"
op_mini = "*"
op_mob = "*"
opera = "< 78"
safari = "*"
samsung_mob = "< 16"
2 changes: 2 additions & 0 deletions polyfills/TypedArray/prototype/at/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// use "Int8Array" as a proxy for support of "TypedArray" subclasses
'Int8Array' in self && 'at' in self.Int8Array.prototype
38 changes: 38 additions & 0 deletions polyfills/TypedArray/prototype/at/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* global CreateMethodProperty, Get, ToIntegerOrInfinity, ToString */
// 23.2.3.1. %TypedArray%.prototype.at ( index )
(function () {
function at(index) {
// 1. Let O be the this value.
var O = this;
// 2. Perform ? ValidateTypedArray(O).
// TODO: Add ValidateTypedArray
// 3. Let len be O.[[ArrayLength]].
var len = O.length;
// 4. Let relativeIndex be ? ToIntegerOrInfinity(index).
var relativeIndex = ToIntegerOrInfinity(index);
// 5. If relativeIndex ≥ 0, then
// 5.a. Let k be relativeIndex.
// 6. Else,
// 6.a. Let k be len + relativeIndex.
var k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex;
// 7. If k < 0 or k ≥ len, return undefined.
if (k < 0 || k >= len) return undefined;
// 8. Return ! Get(O, ! ToString(𝔽(k))).
return Get(O, ToString(k));
}

if ('__proto__' in self.Int8Array.prototype) {
// set this on the underlying "TypedArrayPrototype", which is shared with all "TypedArray" subclasses
CreateMethodProperty(self.Int8Array.prototype.__proto__, 'at', at);
} else {
CreateMethodProperty(self.Int8Array.prototype, 'at', at);
CreateMethodProperty(self.Uint8Array.prototype, 'at', at);
CreateMethodProperty(self.Uint8ClampedArray.prototype, 'at', at);
CreateMethodProperty(self.Int16Array.prototype, 'at', at);
CreateMethodProperty(self.Uint16Array.prototype, 'at', at);
CreateMethodProperty(self.Int32Array.prototype, 'at', at);
CreateMethodProperty(self.Uint32Array.prototype, 'at', at);
CreateMethodProperty(self.Float32Array.prototype, 'at', at);
CreateMethodProperty(self.Float64Array.prototype, 'at', at);
}
})();
63 changes: 63 additions & 0 deletions polyfills/TypedArray/prototype/at/tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* eslint-env mocha, browser */
/* global proclaim, Int8Array */

// use "Int8Array" as a proxy for all "TypedArray" subclasses
if ('Int8Array' in self) {
it('is a function', function () {
proclaim.isFunction(Int8Array.prototype.at);
});

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

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

it('is not enumerable', function () {
if ('__proto__' in Int8Array.prototype) {
proclaim.isNotEnumerable(Int8Array.prototype.__proto__, 'at');
} else {
proclaim.isNotEnumerable(Int8Array.prototype, 'at');
}
});

describe('at', function () {
var supportsGetters = (function() {
try {
var a = {};
Object.defineProperty(a, "t", {
configurable: true,
enumerable: false,
get: function() {
return true;
},
set: undefined
});
return !!a.t;
} catch (e) {
return false;
}
})();

// `new Int8Array(length)` fails with "Getters & setters cannot be defined on this javascript engine" in IE8
// due to a bug in the `ArrayBuffer` polyfill: https://github.com/inexorabletash/polyfill/issues/23
if (supportsGetters) {
it('retrieves values by index for typed arrays', function () {
var typedArray = new Int8Array(3);
typedArray[0] = 1;
typedArray[1] = 2;
typedArray[2] = 3;
proclaim.equal(typedArray.at(undefined), 1);
proclaim.equal(typedArray.at(-4), undefined);
proclaim.equal(typedArray.at(-2), 2);
proclaim.equal(typedArray.at(-0.5), 1);
proclaim.equal(typedArray.at(0), 1);
proclaim.equal(typedArray.at(0.5), 1);
proclaim.equal(typedArray.at(2), 3);
proclaim.equal(typedArray.at(4), undefined);
});
}
});
}
23 changes: 23 additions & 0 deletions polyfills/_ESAbstract/LengthOfArrayLike/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
dependencies = [
"_ESAbstract.Get",
"_ESAbstract.ToLength",
]
spec = "https://tc39.github.io/ecma262/#sec-lengthofarraylike"

[browsers]
android = "*"
bb = "*"
chrome = "*"
edge = "*"
edge_mob = "*"
firefox = "*"
firefox_mob = "*"
ie = "*"
ie_mob = "*"
ios_chr = "*"
ios_saf = "*"
op_mini = "*"
op_mob = "*"
opera = "*"
safari = "*"
samsung_mob = "*"
6 changes: 6 additions & 0 deletions polyfills/_ESAbstract/LengthOfArrayLike/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* global Get, ToLength */
// 7.3.19. LengthOfArrayLike ( obj )
function LengthOfArrayLike(obj) { // eslint-disable-line no-unused-vars
// 1. Return ℝ(? ToLength(? Get(obj, "length"))).
return ToLength(Get(obj, 'length'));
}
22 changes: 22 additions & 0 deletions polyfills/_ESAbstract/ToIntegerOrInfinity/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
dependencies = [
"_ESAbstract.ToNumber",
]
spec = "https://tc39.github.io/ecma262/#sec-tointegerorinfinity"

[browsers]
android = "*"
bb = "*"
chrome = "*"
edge = "*"
edge_mob = "*"
firefox = "*"
firefox_mob = "*"
ie = "*"
ie_mob = "*"
ios_chr = "*"
ios_saf = "*"
op_mini = "*"
op_mob = "*"
opera = "*"
safari = "*"
samsung_mob = "*"
18 changes: 18 additions & 0 deletions polyfills/_ESAbstract/ToIntegerOrInfinity/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* global ToNumber */
// 7.1.5. ToIntegerOrInfinity ( argument )
function ToIntegerOrInfinity(argument) { // eslint-disable-line no-unused-vars
// 1. Let number be ? ToNumber(argument).
var number = ToNumber(argument);
// 2. If number is NaN, +0𝔽, or -0𝔽, return 0.
if (isNaN(number) || number === 0 || 1/number === -Infinity) return 0;
// 3. If number is +∞𝔽, return +∞.
if (number === Infinity) return Infinity;
// 4. If number is -∞𝔽, return -∞.
if (number === -Infinity) return -Infinity;
// 5. Let integer be floor(abs(ℝ(number))).
var integer = Math.floor(Math.abs(number));
// 6. If number < +0𝔽, set integer to -integer.
if (number < 0) integer = -integer;
// 7. Return integer.
return integer;
}

0 comments on commit 29c6814

Please sign in to comment.