Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions polyfills/Iterator/prototype/chunks/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
aliases = [ "es2027" ]
dependencies = [
"_ESAbstract.CreateIterResultObject",
"_ESAbstract.CreateMethodProperty",
"_ESAbstract.Get",
"_ESAbstract.IsInteger",
"_ESAbstract.IteratorClose",
"_ESAbstract.IteratorStepValue",
"_ESAbstract.NormalCompletion",
"_ESAbstract.ThrowCompletion",
"_ESAbstract.Type",
"Iterator",
"Iterator.prototype.take",
"Symbol.iterator",
]
spec = "https://tc39.es/ecma262/#sec-iterator.prototype.chunks"
docs = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/chunks"

[browsers]
android = "*"
bb = "*"
chrome = "*"
edge = "*"
edge_mob = "*"
firefox = "<154"
firefox_mob = "<154"
ie = "*"
ie_mob = "*"
opera = "*"
op_mob = "*"
safari = "*"
ios_saf = "*"
samsung_mob = "*"
1 change: 1 addition & 0 deletions polyfills/Iterator/prototype/chunks/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"Iterator" in self && "chunks" in self.Iterator.prototype;
115 changes: 115 additions & 0 deletions polyfills/Iterator/prototype/chunks/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* global CreateIterResultObject, CreateMethodProperty, Get, IsInteger, Iterator, IteratorClose, IteratorStepValue, NormalCompletion, Symbol, ThrowCompletion, Type */

var IteratorHelperPrototype = (function () {
var iterator = Object.create(Iterator.prototype);
iterator[Symbol.iterator] = function () {
return {
next: function () {
return { value: undefined, done: true };
}
};
};
// use `Iterator.prototype.take` as a way to get `IteratorHelperPrototype`
var iteratorHelper = iterator.take(0);
return Object.getPrototypeOf(iteratorHelper);
})();

// 27.1.3.3.1 Iterator.prototype.chunks ( chunkSize )
CreateMethodProperty(Iterator.prototype, "chunks", function chunks(chunkSize) {
// 1. Let obj be the this value.
var obj = this;
// 2. If obj is not an Object, throw a TypeError exception.
if (Type(obj) !== "object") {
throw new TypeError("`this` is not an object");
}
// 3. Let iterated be the Iterator Record { [[Iterator]]: obj, [[NextMethod]]: undefined, [[Done]]: false }.
var iterated = {
"[[Iterator]]": obj,
"[[NextMethod]]": undefined,
"[[Done]]": false
};
// 4. If chunkSize is not an integral Number, then
if (!IsInteger(chunkSize)) {
// a. Let error be ThrowCompletion(a newly created TypeError object).
var error = ThrowCompletion(new TypeError("`chunkSize` is not an integer"));
// b. Return ? IteratorClose(iterated, error).
return IteratorClose(iterated, error);
}
// 5. If chunkSize is not in the inclusive interval from 1𝔽 to 𝔽(2**32 - 1), then
if (chunkSize < 1 || chunkSize > Math.pow(2, 32) - 1) {
// a. Let error be ThrowCompletion(a newly created RangeError object).
error = ThrowCompletion(new RangeError("`chunkSize` is invalid"));
// b. Return ? IteratorClose(iterated, error).
return IteratorClose(iterated, error);
}
// 6. Set iterated to ? GetIteratorDirect(obj).
iterated = {
"[[Iterator]]": obj,
"[[NextMethod]]": Get(obj, "next"),
"[[Done]]": false
};
// 7. Let closure be a new Abstract Closure with no parameters that captures iterated and chunkSize and performs the following steps when called:
// 8. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterators]] »).
var result = Object.create(IteratorHelperPrototype);
result["[[Done]]"] = false;

// a. Let buffer be a new empty List.
var buffer = [];

CreateMethodProperty(result, "next", function () {
if (this["[[Done]]"] === true) {
return CreateIterResultObject(undefined, true);
}

// b. Repeat,
while (true) {
// i. Let value be ? IteratorStepValue(iterated).
try {
var value = IteratorStepValue(iterated);
} catch (_error) {
this["[[Done]]"] = true;
throw _error;
}
// ii. If value is DONE, then
if (value === IteratorStepValue.DONE) {
this["[[Done]]"] = true;
// 1. If buffer is not empty, then
if (buffer.length > 0) {
// a. Perform Completion(Yield(CreateArrayFromList(buffer))).
return CreateIterResultObject(buffer.slice(), true);
}
// 2. Return ReturnCompletion(undefined).
return CreateIterResultObject(undefined, true);
}
// iii. Append value to buffer.
buffer.push(value);
// iv. If the number of elements in buffer is ℝ(chunkSize), then
if (buffer.length === chunkSize) {
// 1. Let completion be Completion(Yield(CreateArrayFromList(buffer))).
try {
var completion = CreateIterResultObject(buffer.slice(), false);
}
// 2. IfAbruptCloseIterator(completion, iterated).
catch (err) {
this["[[Done]]"] = true;
return IteratorClose(iterated, ThrowCompletion(err));
}
// 3. Set buffer to a new empty List.
buffer = [];
return completion;
}
}
});

CreateMethodProperty(result, "return", function (value) {
if (this["[[Done]]"] !== true) {
IteratorClose(iterated, NormalCompletion(value));
this["[[Done]]"] = true;
}
return CreateIterResultObject(undefined, true);
});

// 9. Set result.[[UnderlyingIterators]] to « iterated ».
// 10. Return result.
return result;
});
75 changes: 75 additions & 0 deletions polyfills/Iterator/prototype/chunks/polyfill.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* global Iterator */

it("is a function", function () {
proclaim.isFunction(Iterator.prototype.chunks);
});

it("has correct arity", function () {
proclaim.arity(Iterator.prototype.chunks, 1);
});

it("has correct name", function () {
proclaim.hasName(Iterator.prototype.chunks, "chunks");
});

it("is not enumerable", function () {
proclaim.isNotEnumerable(Iterator.prototype, "chunks");
});

describe("chunks", function () {
function TestIterator(arr) {
var i = -1;
this.next = function () {
i++;
if (arr[i] === "error") {
throw new Error("uh oh");
}
return { value: arr[i], done: i >= arr.length };
};
}
TestIterator.prototype = Iterator.prototype;

it("should chunk an iterator", function () {
var iter = new TestIterator([1, 2, 3]).chunks(2);
proclaim.deepStrictEqual(iter.next().value, [1, 2]);
proclaim.deepStrictEqual(iter.next().value, [3]);
proclaim.equal(iter.next().value, undefined);

iter = new TestIterator([1, 2, 3, 4]).chunks(2);
proclaim.deepStrictEqual(iter.next().value, [1, 2]);
proclaim.deepStrictEqual(iter.next().value, [3, 4]);
proclaim.equal(iter.next().value, undefined);
});

it("should throw for invalid `chunkSize`", function () {
proclaim.throws(function () {
new TestIterator([1, 2, 3]).chunks(NaN);
}, TypeError);
proclaim.throws(function () {
new TestIterator([1, 2, 3]).chunks(1.5);
}, TypeError);
proclaim.throws(function () {
new TestIterator([1, 2, 3]).chunks(0);
}, RangeError);
proclaim.throws(function () {
new TestIterator([1, 2, 3]).chunks(Math.pow(2, 32));
}, RangeError);
});

it("should handle errors during iteration", function () {
var iter = new TestIterator([1, 2, "error", 4]).chunks(1);
proclaim.deepStrictEqual(iter.next().value, [1]);
proclaim.deepStrictEqual(iter.next().value, [2]);
proclaim.throws(function () {
iter.next();
}, Error);
proclaim.equal(iter.next().value, undefined);
});

it("should return an object with the right prototype", function () {
var iter = new TestIterator([]).chunks(1);
// use `Iterator.prototype.take` as a way to get `IteratorHelperPrototype`
proclaim.isFunction(iter.take);
proclaim.equal(Object.getPrototypeOf(iter), Object.getPrototypeOf(iter.take(0)));
});
});
32 changes: 32 additions & 0 deletions polyfills/Iterator/prototype/includes/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
aliases = [ "es2027" ]
dependencies = [
"_ESAbstract.CreateMethodProperty",
"_ESAbstract.Get",
"_ESAbstract.IsInteger",
"_ESAbstract.IteratorClose",
"_ESAbstract.IteratorStepValue",
"_ESAbstract.NormalCompletion",
"_ESAbstract.SameValueZero",
"_ESAbstract.ThrowCompletion",
"_ESAbstract.Type",
"Iterator",
"Number.MAX_SAFE_INTEGER",
]
spec = "https://tc39.es/ecma262/#sec-iterator.prototype.includes"
docs = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/includes"

[browsers]
android = "*"
bb = "*"
chrome = "<154"
edge = "*"
edge_mob = "*"
firefox = "<154"
firefox_mob = "<154"
ie = "*"
ie_mob = "*"
opera = "<138"
op_mob = "<103"
safari = "*"
ios_saf = "*"
samsung_mob = "*"
1 change: 1 addition & 0 deletions polyfills/Iterator/prototype/includes/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"Iterator" in self && "includes" in self.Iterator.prototype;
75 changes: 75 additions & 0 deletions polyfills/Iterator/prototype/includes/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* global CreateMethodProperty, Get, IsInteger, Iterator, IteratorClose, IteratorStepValue, NormalCompletion, SameValueZero, ThrowCompletion, Type */
// 27.1.3.3.9 Iterator.prototype.includes ( searchElement [ , skippedElements ] )
CreateMethodProperty(Iterator.prototype, "includes", function includes(searchElement /* , skippedElements */) {
// 1. Let obj be the this value.
var obj = this;
// 2. If obj is not an Object, throw a TypeError exception.
if (Type(obj) !== "object") {
throw new TypeError("`this` is not an object");
}
// 3. Let iterated be the Iterator Record { [[Iterator]]: obj, [[NextMethod]]: undefined, [[Done]]: false }.
var iterated = {
"[[Iterator]]": obj,
"[[NextMethod]]": undefined,
"[[Done]]": false
};
// 4. If skippedElements is undefined, then
var skippedElements = arguments[1];
if (skippedElements === undefined) {
// a. Let toSkip be +0𝔽.
var toSkip = 0;
}
// 5. Else,
else {
// a. If skippedElements is not one of +∞𝔽, -∞𝔽, or an integral Number, then
if (skippedElements !== Infinity && skippedElements !== -Infinity && !IsInteger(skippedElements)) {
// i. Let error be ThrowCompletion(a newly created TypeError object).
var error = ThrowCompletion(new TypeError("`skippedElements` is not an integer"));
// ii. Return ? IteratorClose(iterated, error).
return IteratorClose(iterated, error);
}
// b. Let toSkip be skippedElements.
toSkip = skippedElements;
}
// 6. If toSkip < -0𝔽, then
if (toSkip < 0) {
// a. Let error be ThrowCompletion(a newly created RangeError object).
error = ThrowCompletion(new RangeError("`skippedElements` is negative"));
// b. Return ? IteratorClose(iterated, error).
return IteratorClose(iterated, error);
}
// 7. If toSkip is finite and toSkip > 𝔽(2**53 - 1), then
if (toSkip !== Infinity && toSkip > Number.MAX_SAFE_INTEGER) {
// a. Let error be ThrowCompletion(a newly created RangeError object).
error = ThrowCompletion(new RangeError("`skippedElements` is greater than MAX_SAFE_INTEGER"));
// b. Return ? IteratorClose(iterated, error).
return IteratorClose(iterated, error);
}
// 8. Let skipped be +0𝔽.
var skipped = 0;
// 9. Set iterated to ? GetIteratorDirect(obj).
iterated = {
"[[Iterator]]": obj,
"[[NextMethod]]": Get(obj, "next"),
"[[Done]]": false
};
// 10. Repeat,
while (true) {
// a. Let value be ? IteratorStepValue(iterated).
var value = IteratorStepValue(iterated);
// b. If value is DONE, return false.
if (value === IteratorStepValue.DONE) {
return false;
}
// c. If skipped < toSkip, then
if (skipped < toSkip) {
// i. Set skipped to skipped + 1𝔽.
skipped++;
}
// d. Else if SameValueZero(value, searchElement) is true, then
else if (SameValueZero(value, searchElement) === true) {
// i. Return ? IteratorClose(iterated, NormalCompletion(true)).
return IteratorClose(iterated, NormalCompletion(true));
}
}
});
54 changes: 54 additions & 0 deletions polyfills/Iterator/prototype/includes/polyfill.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* global Iterator */

it("is a function", function () {
proclaim.isFunction(Iterator.prototype.includes);
});

it("has correct arity", function () {
proclaim.arity(Iterator.prototype.includes, 1);
});

it("has correct name", function () {
proclaim.hasName(Iterator.prototype.includes, "includes");
});

it("is not enumerable", function () {
proclaim.isNotEnumerable(Iterator.prototype, "includes");
});

describe("includes", function () {
function TestIterator(arr) {
var i = -1;
this.next = function () {
i++;
return { value: arr[i], done: i >= arr.length };
};
}
TestIterator.prototype = Iterator.prototype;

it("should check whether an iterator includes an element", function () {
proclaim.isTrue(new TestIterator(["a", "b", "c"]).includes("a"));
proclaim.isTrue(new TestIterator(["a", "b", "c"]).includes("b", 1));
proclaim.isFalse(new TestIterator(["a", "b", "c"]).includes("d"));
proclaim.isFalse(new TestIterator(["a", "b", "c"]).includes("b", 2));
proclaim.isFalse(new TestIterator(["a", "b", "c"]).includes("b", Infinity));
});

it("should throw for invalid `skippedElements`", function () {
proclaim.throws(function () {
new TestIterator(["a", "b", "c"]).includes("a", NaN);
}, TypeError);
proclaim.throws(function () {
new TestIterator(["a", "b", "c"]).includes("a", -1);
}, RangeError);
proclaim.throws(function () {
new TestIterator(["a", "b", "c"]).includes("a", -Infinity);
}, RangeError);
proclaim.throws(function () {
new TestIterator(["a", "b", "c"]).includes("a", .5);
}, TypeError);
proclaim.throws(function () {
new TestIterator(["a", "b", "c"]).includes("a", Number.MAX_SAFE_INTEGER + 1);
}, RangeError);
});
});
Loading
Loading