initial
This commit is contained in:
commit
5faef796d4
8 changed files with 2033 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules/
|
550
dist/index.js
vendored
Normal file
550
dist/index.js
vendored
Normal file
|
@ -0,0 +1,550 @@
|
|||
// src/index.ts
|
||||
var DoneIteratorResult = Object.freeze({ value: void 0, done: true });
|
||||
function hasMethods(methods, obj) {
|
||||
return methods.every((method) => typeof obj[method] === "function");
|
||||
}
|
||||
function isIterable(value) {
|
||||
return typeof value[Symbol.iterator] === "function";
|
||||
}
|
||||
function isIterator(value) {
|
||||
return typeof value.next === "function";
|
||||
}
|
||||
function isBuffer(value) {
|
||||
return ArrayBuffer.isView(value);
|
||||
}
|
||||
function isArrayLike(value) {
|
||||
return Array.isArray(value) || value instanceof Array;
|
||||
}
|
||||
var IteratorEnumerator = class _IteratorEnumerator {
|
||||
_iterator;
|
||||
_consumed = false;
|
||||
_current;
|
||||
get current() {
|
||||
return this._current;
|
||||
}
|
||||
constructor(iterator) {
|
||||
this._iterator = iterator;
|
||||
}
|
||||
static from(iterator) {
|
||||
return new _IteratorEnumerator(iterator);
|
||||
}
|
||||
moveNext() {
|
||||
if (!this._consumed) {
|
||||
const { value, done } = this._iterator.next();
|
||||
this._current = value;
|
||||
if (done) {
|
||||
this._consumed = true;
|
||||
}
|
||||
return !done;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
reset() {
|
||||
}
|
||||
toIterator() {
|
||||
return this;
|
||||
}
|
||||
next(...[_value]) {
|
||||
const done = this.moveNext();
|
||||
return { value: this.current, done };
|
||||
}
|
||||
return(value) {
|
||||
return this._iterator.return?.(value) ?? DoneIteratorResult;
|
||||
}
|
||||
throw(e) {
|
||||
return this._iterator.throw?.(e) ?? DoneIteratorResult;
|
||||
}
|
||||
};
|
||||
var CachedIteratorEnumerator = class _CachedIteratorEnumerator {
|
||||
_iterator;
|
||||
_cache = [];
|
||||
_index = -1;
|
||||
get current() {
|
||||
return this._cache[this._index];
|
||||
}
|
||||
constructor(iterator) {
|
||||
this._iterator = new IteratorEnumerator(iterator);
|
||||
}
|
||||
static from(iterator) {
|
||||
return new _CachedIteratorEnumerator(iterator);
|
||||
}
|
||||
moveNext() {
|
||||
this._index += 1;
|
||||
if (this._cache.length > this._index) {
|
||||
return true;
|
||||
} else if (this._iterator.moveNext()) {
|
||||
this._cache.push(this._iterator.current);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
reset() {
|
||||
this._index = -1;
|
||||
}
|
||||
toIterator() {
|
||||
return this;
|
||||
}
|
||||
next(...[_value]) {
|
||||
const done = this.moveNext();
|
||||
return { value: this.current, done };
|
||||
}
|
||||
return(value) {
|
||||
return this._iterator.return(value);
|
||||
}
|
||||
throw(e) {
|
||||
return this._iterator.throw(e);
|
||||
}
|
||||
};
|
||||
var IterableEnumerator = class {
|
||||
_iterable;
|
||||
_factory;
|
||||
_enumerator;
|
||||
get current() {
|
||||
return this._enumerator?.current;
|
||||
}
|
||||
constructor(iterable, factory = IteratorEnumerator.from) {
|
||||
this._iterable = iterable;
|
||||
this._factory = factory;
|
||||
this._enumerator = this._createEnumerator();
|
||||
}
|
||||
static fromIterable(iterable, factory) {
|
||||
return new this(iterable, factory);
|
||||
}
|
||||
moveNext() {
|
||||
return this._enumerator?.moveNext() ?? false;
|
||||
}
|
||||
_createIterator() {
|
||||
return this._iterable[Symbol.iterator]();
|
||||
}
|
||||
_createEnumerator() {
|
||||
return this._factory(this._createIterator());
|
||||
}
|
||||
reset() {
|
||||
this._enumerator = this._createEnumerator();
|
||||
}
|
||||
toIterator() {
|
||||
return this._createIterator();
|
||||
}
|
||||
next(...[_value]) {
|
||||
const done = !this.moveNext();
|
||||
return { value: this.current, done };
|
||||
}
|
||||
return(value) {
|
||||
if (isIterator(this._enumerator)) {
|
||||
return this._enumerator?.return?.(value) || DoneIteratorResult;
|
||||
} else {
|
||||
return DoneIteratorResult;
|
||||
}
|
||||
}
|
||||
throw(e) {
|
||||
if (isIterator(this._enumerator)) {
|
||||
return this._enumerator?.throw?.(e) || DoneIteratorResult;
|
||||
} else {
|
||||
return DoneIteratorResult;
|
||||
}
|
||||
}
|
||||
};
|
||||
function toArrayLikeBuffer(buffer) {
|
||||
return Object.defineProperty(buffer, "length", {
|
||||
get: function() {
|
||||
return buffer.byteLength;
|
||||
}
|
||||
});
|
||||
}
|
||||
var ArrayEnumerator = class _ArrayEnumerator {
|
||||
_array;
|
||||
_index = -1;
|
||||
get current() {
|
||||
return this._array[this._index];
|
||||
}
|
||||
constructor(array) {
|
||||
this._array = array;
|
||||
}
|
||||
static from(array) {
|
||||
if (ArrayBuffer.isView(array)) {
|
||||
return new _ArrayEnumerator(toArrayLikeBuffer(array));
|
||||
} else {
|
||||
return new _ArrayEnumerator(array);
|
||||
}
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this._array[Symbol.iterator]();
|
||||
}
|
||||
setIndex(index) {
|
||||
this._index = index;
|
||||
}
|
||||
moveNext() {
|
||||
this._index += 1;
|
||||
return this._index < this._array.length;
|
||||
}
|
||||
reset() {
|
||||
this._index = -1;
|
||||
}
|
||||
toIterator() {
|
||||
return this._array[Symbol.iterator]();
|
||||
}
|
||||
next(...[_value]) {
|
||||
const done = this.moveNext();
|
||||
return { value: this.current, done };
|
||||
}
|
||||
return(_value) {
|
||||
return DoneIteratorResult;
|
||||
}
|
||||
throw(_e) {
|
||||
return DoneIteratorResult;
|
||||
}
|
||||
};
|
||||
var Enumerator = class _Enumerator {
|
||||
_enumerator;
|
||||
_index = 0;
|
||||
get current() {
|
||||
return this._enumerator.current;
|
||||
}
|
||||
constructor(enumerator) {
|
||||
this._enumerator = enumerator;
|
||||
}
|
||||
static fromIterable(iterable) {
|
||||
if (isArrayLike(iterable) || ArrayBuffer.isView(iterable)) {
|
||||
return ArrayEnumerator.from(iterable);
|
||||
} else {
|
||||
return new this(new IterableEnumerator(iterable));
|
||||
}
|
||||
}
|
||||
static fromIterator(iterator, cache = true) {
|
||||
if (cache) {
|
||||
return new CachedIteratorEnumerator(iterator);
|
||||
} else {
|
||||
return new IteratorEnumerator(iterator);
|
||||
}
|
||||
}
|
||||
static toIterator(enumerator) {
|
||||
return new this(enumerator);
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this.toIterator();
|
||||
}
|
||||
toIterator() {
|
||||
return _Enumerator.toIterator(this);
|
||||
}
|
||||
moveNext() {
|
||||
this._index += 1;
|
||||
return this._enumerator.moveNext();
|
||||
}
|
||||
reset() {
|
||||
this._enumerator.reset();
|
||||
}
|
||||
next(...[_value]) {
|
||||
const done = this.moveNext();
|
||||
return { value: this.current, done };
|
||||
}
|
||||
return(_value) {
|
||||
return DoneIteratorResult;
|
||||
}
|
||||
throw(_e) {
|
||||
return DoneIteratorResult;
|
||||
}
|
||||
};
|
||||
var HelperEnumerator = class _HelperEnumerator {
|
||||
_enumerator;
|
||||
_index = 0;
|
||||
get current() {
|
||||
return this._enumerator.current;
|
||||
}
|
||||
constructor(enumerator) {
|
||||
this._enumerator = enumerator;
|
||||
}
|
||||
static toIterator(enumerator) {
|
||||
return new this(enumerator);
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this.toIterator();
|
||||
}
|
||||
toIterator() {
|
||||
return _HelperEnumerator.toIterator(this);
|
||||
}
|
||||
moveNext() {
|
||||
this._index += 1;
|
||||
return this._enumerator.moveNext();
|
||||
}
|
||||
reset() {
|
||||
this._enumerator.reset();
|
||||
}
|
||||
next(...[_value]) {
|
||||
const done = this.moveNext();
|
||||
return { value: this.current, done };
|
||||
}
|
||||
return(_value) {
|
||||
return DoneIteratorResult;
|
||||
}
|
||||
throw(_e) {
|
||||
return DoneIteratorResult;
|
||||
}
|
||||
};
|
||||
var DropEnumerator = class extends HelperEnumerator {
|
||||
_limit;
|
||||
constructor(enumerator, limit) {
|
||||
super(enumerator);
|
||||
this._limit = limit;
|
||||
}
|
||||
moveNext() {
|
||||
let next = super.moveNext();
|
||||
while (this._limit > 0 && next) {
|
||||
next = super.moveNext();
|
||||
this._limit -= 1;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
};
|
||||
var FilterEnumerator = class extends HelperEnumerator {
|
||||
_filter;
|
||||
constructor(enumerator, filter) {
|
||||
super(enumerator);
|
||||
this._filter = filter;
|
||||
}
|
||||
moveNext() {
|
||||
let next = super.moveNext();
|
||||
while (next && !this._filter(this.current, this._index)) {
|
||||
next = super.moveNext();
|
||||
}
|
||||
return next;
|
||||
}
|
||||
};
|
||||
var FlatMapEnumerator = class {
|
||||
_enumerator;
|
||||
_flatMap;
|
||||
_inner;
|
||||
_index = -1;
|
||||
constructor(enumerator, flatMap) {
|
||||
this._enumerator = enumerator;
|
||||
this._flatMap = flatMap;
|
||||
}
|
||||
get current() {
|
||||
return this._inner?.current;
|
||||
}
|
||||
moveNext() {
|
||||
if (this._inner && this._inner.moveNext()) {
|
||||
return true;
|
||||
}
|
||||
const next = this._enumerator.moveNext();
|
||||
if (!next) {
|
||||
return false;
|
||||
}
|
||||
this._index += 1;
|
||||
this._inner = this._flatMap(this._enumerator.current, this._index);
|
||||
return this._inner.moveNext();
|
||||
}
|
||||
reset() {
|
||||
this._index = -1;
|
||||
this._inner = void 0;
|
||||
this._enumerator.reset();
|
||||
}
|
||||
toIterator() {
|
||||
return HelperEnumerator.toIterator(this);
|
||||
}
|
||||
};
|
||||
var MapEnumerator = class {
|
||||
_enumerator;
|
||||
_map;
|
||||
_current;
|
||||
_index = -1;
|
||||
get current() {
|
||||
return this._current;
|
||||
}
|
||||
constructor(enumerator, map) {
|
||||
this._enumerator = enumerator;
|
||||
this._map = map;
|
||||
}
|
||||
toIterator() {
|
||||
return HelperEnumerator.toIterator(this);
|
||||
}
|
||||
moveNext() {
|
||||
this._index += 1;
|
||||
const next = this._enumerator.moveNext();
|
||||
if (next) {
|
||||
this._current = this._map(this._enumerator.current, this._index);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
reset() {
|
||||
this._index = -1;
|
||||
this._enumerator.reset();
|
||||
}
|
||||
};
|
||||
var TakeEnumerator = class extends HelperEnumerator {
|
||||
_limit;
|
||||
constructor(enumerator, limit) {
|
||||
super(enumerator);
|
||||
this._limit = limit;
|
||||
}
|
||||
moveNext() {
|
||||
if (this._limit < 0) {
|
||||
return false;
|
||||
} else {
|
||||
super.moveNext();
|
||||
this._limit -= 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
var FusedEnumerator = class {
|
||||
_enumerators;
|
||||
_index = 0;
|
||||
get current() {
|
||||
return this._cur()?.current;
|
||||
}
|
||||
constructor(enumerators) {
|
||||
this._enumerators = enumerators;
|
||||
}
|
||||
_cur() {
|
||||
return this._enumerators[this._index];
|
||||
}
|
||||
_done() {
|
||||
return this._index >= this._enumerators.length;
|
||||
}
|
||||
toIterator() {
|
||||
return HelperEnumerator.toIterator(this);
|
||||
}
|
||||
moveNext() {
|
||||
while (!this._done() && !this._cur().moveNext()) {
|
||||
this._index += 1;
|
||||
}
|
||||
return this._done();
|
||||
}
|
||||
reset() {
|
||||
const len = this._enumerators.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
this._enumerators[i].reset();
|
||||
}
|
||||
this._index = 0;
|
||||
}
|
||||
};
|
||||
var Enumerable = class _Enumerable {
|
||||
_enumerator;
|
||||
constructor(enumerator) {
|
||||
this._enumerator = enumerator;
|
||||
}
|
||||
static from(value) {
|
||||
if (this.isEnumerable(value)) {
|
||||
return value;
|
||||
} else if (this.isEnumerator(value)) {
|
||||
return new _Enumerable(value);
|
||||
} else if (isIterable(value)) {
|
||||
const enumerator = Enumerator.fromIterable(value);
|
||||
if (isArrayLike(value)) {
|
||||
return new ArrayEnumerble(enumerator);
|
||||
} else {
|
||||
return new _Enumerable(enumerator);
|
||||
}
|
||||
} else if (isIterator(value)) {
|
||||
return new _Enumerable(
|
||||
Enumerator.fromIterator(value)
|
||||
);
|
||||
} else {
|
||||
throw new TypeError("value is not enumerable");
|
||||
}
|
||||
}
|
||||
static isEnumerable(value) {
|
||||
return typeof value["enumerator"] === "function";
|
||||
}
|
||||
static isEnumerator(value) {
|
||||
return hasMethods(["moveNext", "reset", "toIterator"], value);
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this._enumerator.toIterator();
|
||||
}
|
||||
at(index) {
|
||||
while (index >= 0 && this._enumerator.moveNext()) {
|
||||
index -= 1;
|
||||
}
|
||||
const value = this._enumerator.current;
|
||||
this._enumerator.reset();
|
||||
return value;
|
||||
}
|
||||
atOrDefault(index, defaultValue) {
|
||||
const value = this.at(index);
|
||||
return value || defaultValue;
|
||||
}
|
||||
atOrElse(index, defaultValue) {
|
||||
const value = this.at(index);
|
||||
return value || defaultValue();
|
||||
}
|
||||
concat(other) {
|
||||
return new _Enumerable(
|
||||
new FusedEnumerator([this._enumerator, other.enumerator()])
|
||||
);
|
||||
}
|
||||
drop(limit) {
|
||||
return new _Enumerable(new DropEnumerator(this._enumerator, limit));
|
||||
}
|
||||
enumerator() {
|
||||
return this._enumerator;
|
||||
}
|
||||
//entries(): IEnumerator<T> {
|
||||
//}
|
||||
every(predicate) {
|
||||
let index = 0;
|
||||
while (this._enumerator.moveNext()) {
|
||||
if (!predicate(this._enumerator.current, index)) {
|
||||
return false;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
this._enumerator.reset();
|
||||
return true;
|
||||
}
|
||||
filter(predicate) {
|
||||
return new _Enumerable(new FilterEnumerator(this._enumerator, predicate));
|
||||
}
|
||||
flatMap(fn) {
|
||||
return new _Enumerable(new FlatMapEnumerator(this._enumerator, fn));
|
||||
}
|
||||
map(fn) {
|
||||
return new _Enumerable(new MapEnumerator(this._enumerator, fn));
|
||||
}
|
||||
some(predicate) {
|
||||
let index = 0;
|
||||
while (this._enumerator.moveNext()) {
|
||||
if (predicate(this._enumerator.current, index)) {
|
||||
return true;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
this._enumerator.reset();
|
||||
return false;
|
||||
}
|
||||
take(limit) {
|
||||
return new _Enumerable(new TakeEnumerator(this._enumerator, limit));
|
||||
}
|
||||
};
|
||||
var ArrayEnumerble = class extends Enumerable {
|
||||
at(index) {
|
||||
if (this._enumerator instanceof ArrayEnumerator) {
|
||||
this._enumerator.setIndex(index);
|
||||
return this._enumerator.current;
|
||||
} else {
|
||||
return super.at(index);
|
||||
}
|
||||
}
|
||||
};
|
||||
export {
|
||||
ArrayEnumerator,
|
||||
ArrayEnumerble,
|
||||
CachedIteratorEnumerator,
|
||||
DropEnumerator,
|
||||
Enumerable,
|
||||
Enumerator,
|
||||
FilterEnumerator,
|
||||
FlatMapEnumerator,
|
||||
FusedEnumerator,
|
||||
HelperEnumerator,
|
||||
IterableEnumerator,
|
||||
IteratorEnumerator,
|
||||
MapEnumerator,
|
||||
TakeEnumerator,
|
||||
isArrayLike,
|
||||
isBuffer,
|
||||
isIterable,
|
||||
isIterator
|
||||
};
|
489
package-lock.json
generated
Normal file
489
package-lock.json
generated
Normal file
|
@ -0,0 +1,489 @@
|
|||
{
|
||||
"name": "enumerable-ts",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "enumerable-ts",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.3",
|
||||
"folktest": "git+https://git.kitsu.cafe/rowan/folktest.git"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz",
|
||||
"integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz",
|
||||
"integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz",
|
||||
"integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz",
|
||||
"integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz",
|
||||
"integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz",
|
||||
"integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz",
|
||||
"integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz",
|
||||
"integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz",
|
||||
"integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz",
|
||||
"integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz",
|
||||
"integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz",
|
||||
"integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz",
|
||||
"integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz",
|
||||
"integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz",
|
||||
"integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz",
|
||||
"integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz",
|
||||
"integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz",
|
||||
"integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz",
|
||||
"integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz",
|
||||
"integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz",
|
||||
"integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz",
|
||||
"integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz",
|
||||
"integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz",
|
||||
"integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz",
|
||||
"integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz",
|
||||
"integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.25.3",
|
||||
"@esbuild/android-arm": "0.25.3",
|
||||
"@esbuild/android-arm64": "0.25.3",
|
||||
"@esbuild/android-x64": "0.25.3",
|
||||
"@esbuild/darwin-arm64": "0.25.3",
|
||||
"@esbuild/darwin-x64": "0.25.3",
|
||||
"@esbuild/freebsd-arm64": "0.25.3",
|
||||
"@esbuild/freebsd-x64": "0.25.3",
|
||||
"@esbuild/linux-arm": "0.25.3",
|
||||
"@esbuild/linux-arm64": "0.25.3",
|
||||
"@esbuild/linux-ia32": "0.25.3",
|
||||
"@esbuild/linux-loong64": "0.25.3",
|
||||
"@esbuild/linux-mips64el": "0.25.3",
|
||||
"@esbuild/linux-ppc64": "0.25.3",
|
||||
"@esbuild/linux-riscv64": "0.25.3",
|
||||
"@esbuild/linux-s390x": "0.25.3",
|
||||
"@esbuild/linux-x64": "0.25.3",
|
||||
"@esbuild/netbsd-arm64": "0.25.3",
|
||||
"@esbuild/netbsd-x64": "0.25.3",
|
||||
"@esbuild/openbsd-arm64": "0.25.3",
|
||||
"@esbuild/openbsd-x64": "0.25.3",
|
||||
"@esbuild/sunos-x64": "0.25.3",
|
||||
"@esbuild/win32-arm64": "0.25.3",
|
||||
"@esbuild/win32-ia32": "0.25.3",
|
||||
"@esbuild/win32-x64": "0.25.3"
|
||||
}
|
||||
},
|
||||
"node_modules/folktest": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "git+https://git.kitsu.cafe/rowan/folktest.git#cbf48ff3b1334eb883f202a77a5bc89d24534520",
|
||||
"dev": true,
|
||||
"license": "GPL-3.0-or-later"
|
||||
}
|
||||
}
|
||||
}
|
18
package.json
Normal file
18
package.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "enumerable-ts",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "esbuild src/index.ts --bundle --platform=node --format=esm --outfile=./dist/index.js",
|
||||
"test": "./test/index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.3",
|
||||
"folktest": "git+https://git.kitsu.cafe/rowan/folktest.git"
|
||||
}
|
||||
}
|
709
src/index.ts
Normal file
709
src/index.ts
Normal file
|
@ -0,0 +1,709 @@
|
|||
const DoneIteratorResult = Object.freeze({ value: undefined, done: true })
|
||||
|
||||
type Nullable<T> = T | null | undefined
|
||||
|
||||
export interface Predicate<T> {
|
||||
(value: Nullable<T>, index: number): boolean
|
||||
}
|
||||
|
||||
export interface Reducer<T, U = T> {
|
||||
(accumulator: U, value: Nullable<T>, index: number): U
|
||||
}
|
||||
|
||||
export interface Morphism<T, U = T> {
|
||||
(value: Nullable<T>, index: number): U
|
||||
}
|
||||
|
||||
export interface IEnumerator<T> {
|
||||
get current(): Nullable<T>
|
||||
moveNext(): boolean
|
||||
reset(): void
|
||||
toIterator<T>(): Iterator<T>
|
||||
}
|
||||
|
||||
export interface IEnumerable<T> {
|
||||
enumerator(): IEnumerator<T>
|
||||
}
|
||||
|
||||
export interface IEnumeratorFactory<T> {
|
||||
(iterator: Iterator<T>): IEnumerator<T>
|
||||
}
|
||||
|
||||
function hasMethods(methods: PropertyKey[], obj: object): boolean {
|
||||
return methods.every(method => typeof obj[method] === 'function')
|
||||
}
|
||||
|
||||
export function isIterable(value: any): value is Iterable<any> {
|
||||
return typeof value[Symbol.iterator] === 'function'
|
||||
}
|
||||
|
||||
export function isIterator(value: any): value is Iterator<any> {
|
||||
return typeof value.next === 'function'
|
||||
}
|
||||
|
||||
export function isBuffer(value: any): value is ArrayBufferLike {
|
||||
return ArrayBuffer.isView(value)
|
||||
}
|
||||
|
||||
export function isArrayLike(value: any): value is ArrayLike<any> {
|
||||
return Array.isArray(value) || value instanceof Array
|
||||
}
|
||||
|
||||
export class IteratorEnumerator<T> implements IEnumerator<T>, Iterator<T> {
|
||||
private _iterator: Iterator<T>
|
||||
private _consumed: boolean = false
|
||||
private _current: Nullable<T>
|
||||
|
||||
get current(): Nullable<T> {
|
||||
return this._current
|
||||
}
|
||||
|
||||
constructor(iterator: Iterator<T>) {
|
||||
this._iterator = iterator
|
||||
}
|
||||
|
||||
static from<T>(iterator: Iterator<T>): IteratorEnumerator<T> {
|
||||
return new IteratorEnumerator(iterator)
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
if (!this._consumed) {
|
||||
const { value, done } = this._iterator.next()
|
||||
|
||||
this._current = value
|
||||
if (done) {
|
||||
this._consumed = true
|
||||
}
|
||||
|
||||
return !done
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void { }
|
||||
|
||||
toIterator<T>(): Iterator<T> {
|
||||
return this as Iterator<T>
|
||||
}
|
||||
|
||||
next(...[_value]: [] | [any]): IteratorResult<T> {
|
||||
const done = this.moveNext()
|
||||
return { value: this.current, done } as IteratorResult<T>
|
||||
}
|
||||
|
||||
return(value?: any): IteratorResult<T, any> {
|
||||
return this._iterator.return?.(value) ?? DoneIteratorResult
|
||||
}
|
||||
|
||||
throw(e?: any): IteratorResult<T, any> {
|
||||
return this._iterator.throw?.(e) ?? DoneIteratorResult
|
||||
}
|
||||
}
|
||||
|
||||
export class CachedIteratorEnumerator<T> implements IEnumerator<T>, Iterator<T> {
|
||||
private _iterator: IteratorEnumerator<T>
|
||||
private _cache: Nullable<T>[] = []
|
||||
private _index: number = -1
|
||||
|
||||
get current(): Nullable<T> {
|
||||
return this._cache[this._index]
|
||||
}
|
||||
|
||||
constructor(iterator: Iterator<T>) {
|
||||
this._iterator = new IteratorEnumerator(iterator)
|
||||
}
|
||||
|
||||
static from<T>(iterator: Iterator<T>): CachedIteratorEnumerator<T> {
|
||||
return new CachedIteratorEnumerator(iterator)
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
this._index += 1
|
||||
|
||||
if (this._cache.length > this._index) {
|
||||
return true
|
||||
} else if (this._iterator.moveNext()) {
|
||||
this._cache.push(this._iterator.current)
|
||||
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._index = -1
|
||||
}
|
||||
|
||||
toIterator<T>(): Iterator<T> {
|
||||
return this as Iterator<T>
|
||||
}
|
||||
|
||||
next(...[_value]: [] | [any]): IteratorResult<T> {
|
||||
const done = this.moveNext()
|
||||
return { value: this.current, done } as IteratorResult<T>
|
||||
}
|
||||
|
||||
return?(value?: any): IteratorResult<T, any> {
|
||||
return this._iterator.return(value)
|
||||
}
|
||||
|
||||
throw(e?: any): IteratorResult<T, any> {
|
||||
return this._iterator.throw(e)
|
||||
}
|
||||
}
|
||||
|
||||
export class IterableEnumerator<T> implements IEnumerator<T>, Iterator<T> {
|
||||
private _iterable: Iterable<T>
|
||||
private _factory: IEnumeratorFactory<T>
|
||||
private _enumerator: Nullable<IEnumerator<T>>
|
||||
|
||||
get current(): Nullable<T> {
|
||||
return this._enumerator?.current
|
||||
}
|
||||
|
||||
constructor(iterable: Iterable<T>, factory: IEnumeratorFactory<T> = IteratorEnumerator.from) {
|
||||
this._iterable = iterable
|
||||
this._factory = factory
|
||||
this._enumerator = this._createEnumerator()
|
||||
}
|
||||
|
||||
static fromIterable<T>(iterable: Iterable<T>, factory?: IEnumeratorFactory<T>): IEnumerator<T> {
|
||||
return new this(iterable, factory)
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
return this._enumerator?.moveNext() ?? false
|
||||
}
|
||||
|
||||
_createIterator(): Iterator<T> {
|
||||
return this._iterable[Symbol.iterator]()
|
||||
}
|
||||
|
||||
_createEnumerator(): IEnumerator<T> {
|
||||
return this._factory(this._createIterator())
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._enumerator = this._createEnumerator()
|
||||
}
|
||||
|
||||
toIterator<T>(): Iterator<T> {
|
||||
return this._createIterator() as Iterator<T>
|
||||
}
|
||||
|
||||
next(...[_value]: [] | [any]): IteratorResult<T, any> {
|
||||
const done = !this.moveNext()
|
||||
return { value: this.current, done } as IteratorResult<T, any>
|
||||
}
|
||||
|
||||
return?(value?: any): IteratorResult<T, any> {
|
||||
if (isIterator(this._enumerator)) {
|
||||
return this._enumerator?.return?.(value) || DoneIteratorResult
|
||||
} else {
|
||||
return DoneIteratorResult
|
||||
}
|
||||
}
|
||||
|
||||
throw?(e?: any): IteratorResult<T, any> {
|
||||
if (isIterator(this._enumerator)) {
|
||||
return this._enumerator?.throw?.(e) || DoneIteratorResult
|
||||
} else {
|
||||
return DoneIteratorResult
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ugly hack to stamp arraybuffers to be arraylike
|
||||
function toArrayLikeBuffer<T extends ArrayBufferView>(buffer: T): T & ArrayLike<number> {
|
||||
return Object.defineProperty(buffer, 'length', {
|
||||
get: function() { return buffer.byteLength }
|
||||
}) as T & ArrayLike<number>
|
||||
}
|
||||
|
||||
type ArrayType<T extends ArrayLike<any> | ArrayBufferView> = T extends ArrayLike<infer U> ? U : T extends ArrayBufferTypes ? number : never
|
||||
|
||||
export class ArrayEnumerator<T> implements IEnumerator<T>, Iterator<T>, Iterable<T> {
|
||||
private _array: ArrayLike<T>
|
||||
private _index: number = -1
|
||||
|
||||
get current(): Nullable<T> {
|
||||
return this._array[this._index]
|
||||
}
|
||||
|
||||
constructor(array: ArrayLike<T>) {
|
||||
this._array = array
|
||||
}
|
||||
|
||||
static from<A extends ArrayLike<any> | ArrayBufferView>(array: A): ArrayEnumerator<ArrayType<A>> {
|
||||
if (ArrayBuffer.isView(array)) {
|
||||
return new ArrayEnumerator(toArrayLikeBuffer(array))
|
||||
} else {
|
||||
return new ArrayEnumerator(array)
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.iterator](): Iterator<T> {
|
||||
return this._array[Symbol.iterator]()
|
||||
}
|
||||
|
||||
setIndex(index: number) {
|
||||
this._index = index
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
this._index += 1
|
||||
return this._index < this._array.length
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._index = -1
|
||||
}
|
||||
|
||||
toIterator<T>(): Iterator<T> {
|
||||
return this._array[Symbol.iterator]()
|
||||
}
|
||||
|
||||
next(...[_value]: [] | [any]): IteratorResult<T, any> {
|
||||
const done = this.moveNext()
|
||||
return { value: this.current, done } as IteratorResult<T>
|
||||
}
|
||||
|
||||
return?(_value?: any): IteratorResult<T, any> {
|
||||
return DoneIteratorResult
|
||||
}
|
||||
|
||||
throw?(_e?: any): IteratorResult<T, any> {
|
||||
return DoneIteratorResult
|
||||
}
|
||||
}
|
||||
|
||||
export class Enumerator<T> implements IEnumerator<T>, Iterator<T> {
|
||||
protected _enumerator: IEnumerator<T>
|
||||
protected _index: number = 0
|
||||
|
||||
get current(): Nullable<T> {
|
||||
return this._enumerator.current
|
||||
}
|
||||
|
||||
constructor(enumerator: IEnumerator<T>) {
|
||||
this._enumerator = enumerator
|
||||
}
|
||||
|
||||
static fromIterable<T>(iterable: Iterable<T>): IEnumerator<T> {
|
||||
if (isArrayLike(iterable) || ArrayBuffer.isView(iterable)) {
|
||||
return ArrayEnumerator.from(iterable)
|
||||
} else {
|
||||
return new this(new IterableEnumerator(iterable))
|
||||
}
|
||||
}
|
||||
|
||||
static fromIterator<T>(iterator: Iterator<T>, cache: boolean = true): IEnumerator<T> {
|
||||
if (cache) {
|
||||
return new CachedIteratorEnumerator(iterator)
|
||||
} else {
|
||||
return new IteratorEnumerator(iterator)
|
||||
}
|
||||
}
|
||||
|
||||
static toIterator<T>(enumerator: IEnumerator<T>): Iterator<T> {
|
||||
return new this(enumerator)
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this.toIterator()
|
||||
}
|
||||
|
||||
toIterator<T>(): Iterator<T> {
|
||||
return Enumerator.toIterator(this) as Iterator<T>
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
this._index += 1
|
||||
return this._enumerator.moveNext()
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._enumerator.reset()
|
||||
}
|
||||
|
||||
next(...[_value]: [] | [any]): IteratorResult<T, any> {
|
||||
const done = this.moveNext()
|
||||
|
||||
return { value: this.current, done } as IteratorResult<T>
|
||||
}
|
||||
|
||||
return?(_value?: any): IteratorResult<T, any> {
|
||||
return DoneIteratorResult
|
||||
}
|
||||
|
||||
throw?(_e?: any): IteratorResult<T, any> {
|
||||
return DoneIteratorResult
|
||||
}
|
||||
}
|
||||
|
||||
export class HelperEnumerator<T> implements IEnumerator<T>, Iterator<T> {
|
||||
protected _enumerator: IEnumerator<T>
|
||||
protected _index: number = 0
|
||||
|
||||
get current(): Nullable<T> {
|
||||
return this._enumerator.current
|
||||
}
|
||||
|
||||
constructor(enumerator: IEnumerator<T>) {
|
||||
this._enumerator = enumerator
|
||||
}
|
||||
|
||||
static toIterator<T>(enumerator: IEnumerator<T>): Iterator<T> {
|
||||
return new this(enumerator)
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this.toIterator()
|
||||
}
|
||||
|
||||
toIterator<T>(): Iterator<T> {
|
||||
return HelperEnumerator.toIterator(this) as Iterator<T>
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
this._index += 1
|
||||
return this._enumerator.moveNext()
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._enumerator.reset()
|
||||
}
|
||||
|
||||
next(...[_value]: [] | [any]): IteratorResult<T, any> {
|
||||
const done = this.moveNext()
|
||||
|
||||
return { value: this.current, done } as IteratorResult<T>
|
||||
}
|
||||
|
||||
return?(_value?: any): IteratorResult<T, any> {
|
||||
return DoneIteratorResult
|
||||
}
|
||||
|
||||
throw?(_e?: any): IteratorResult<T, any> {
|
||||
return DoneIteratorResult
|
||||
}
|
||||
}
|
||||
|
||||
export class DropEnumerator<T> extends HelperEnumerator<T> {
|
||||
private _limit: number
|
||||
|
||||
constructor(enumerator: IEnumerator<T>, limit: number) {
|
||||
super(enumerator)
|
||||
this._limit = limit
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
let next = super.moveNext()
|
||||
|
||||
while (this._limit > 0 && next) {
|
||||
next = super.moveNext()
|
||||
this._limit -= 1
|
||||
}
|
||||
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
export class FilterEnumerator<T> extends HelperEnumerator<T> {
|
||||
private _filter: Predicate<T>
|
||||
|
||||
constructor(enumerator: IEnumerator<T>, filter: Predicate<T>) {
|
||||
super(enumerator)
|
||||
this._filter = filter
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
let next = super.moveNext()
|
||||
|
||||
while (next && !this._filter(this.current, this._index)) {
|
||||
next = super.moveNext()
|
||||
}
|
||||
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
export class FlatMapEnumerator<T, U = T> implements IEnumerator<U> {
|
||||
private _enumerator: IEnumerator<T>
|
||||
private _flatMap: Morphism<T, IEnumerator<U>>
|
||||
private _inner?: IEnumerator<U>
|
||||
private _index: number = -1
|
||||
|
||||
constructor(enumerator: IEnumerator<T>, flatMap: Morphism<T, IEnumerator<U>>) {
|
||||
this._enumerator = enumerator
|
||||
this._flatMap = flatMap
|
||||
}
|
||||
|
||||
get current(): Nullable<U> {
|
||||
return this._inner?.current
|
||||
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
if (this._inner && this._inner.moveNext()) {
|
||||
return true
|
||||
}
|
||||
|
||||
const next = this._enumerator.moveNext()
|
||||
|
||||
if (!next) {
|
||||
return false
|
||||
}
|
||||
|
||||
this._index += 1
|
||||
this._inner = this._flatMap(this._enumerator.current, this._index)
|
||||
return this._inner.moveNext()
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._index = -1
|
||||
this._inner = undefined
|
||||
this._enumerator.reset()
|
||||
}
|
||||
|
||||
toIterator<T>(): Iterator<T> {
|
||||
return HelperEnumerator.toIterator(this) as Iterator<T>
|
||||
}
|
||||
}
|
||||
|
||||
export class MapEnumerator<T, U = T> implements IEnumerator<U> {
|
||||
private _enumerator: IEnumerator<T>
|
||||
private _map: Morphism<T, U>
|
||||
private _current!: U
|
||||
private _index: number = -1
|
||||
|
||||
get current(): U {
|
||||
return this._current
|
||||
}
|
||||
|
||||
constructor(enumerator: IEnumerator<T>, map: Morphism<T, U>) {
|
||||
this._enumerator = enumerator
|
||||
this._map = map
|
||||
}
|
||||
|
||||
toIterator<U>(): Iterator<U> {
|
||||
return HelperEnumerator.toIterator(this) as Iterator<U>
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
this._index += 1
|
||||
const next = this._enumerator.moveNext()
|
||||
|
||||
if (next) {
|
||||
this._current = this._map(this._enumerator.current, this._index)
|
||||
}
|
||||
|
||||
return next
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._index = -1
|
||||
this._enumerator.reset()
|
||||
}
|
||||
}
|
||||
|
||||
export class TakeEnumerator<T> extends HelperEnumerator<T> {
|
||||
private _limit: number
|
||||
|
||||
constructor(enumerator: IEnumerator<T>, limit: number) {
|
||||
super(enumerator)
|
||||
this._limit = limit
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
if (this._limit < 0) {
|
||||
return false
|
||||
} else {
|
||||
super.moveNext()
|
||||
this._limit -= 1
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class FusedEnumerator<T> implements IEnumerator<T> {
|
||||
private _enumerators: IEnumerator<T>[]
|
||||
private _index: number = 0
|
||||
|
||||
get current(): Nullable<T> {
|
||||
return this._cur()?.current
|
||||
}
|
||||
|
||||
constructor(enumerators: IEnumerator<T>[]) {
|
||||
this._enumerators = enumerators
|
||||
}
|
||||
|
||||
private _cur() {
|
||||
return this._enumerators[this._index]
|
||||
}
|
||||
|
||||
private _done() {
|
||||
return this._index >= this._enumerators.length
|
||||
}
|
||||
|
||||
toIterator<T>(): Iterator<T> {
|
||||
return HelperEnumerator.toIterator(this) as Iterator<T>
|
||||
}
|
||||
|
||||
moveNext(): boolean {
|
||||
while (!this._done() && !this._cur().moveNext()) {
|
||||
this._index += 1
|
||||
}
|
||||
|
||||
return this._done()
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
const len = this._enumerators.length
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
this._enumerators[i].reset()
|
||||
}
|
||||
|
||||
this._index = 0
|
||||
}
|
||||
}
|
||||
|
||||
export class Enumerable<T> implements IEnumerable<T>, Iterable<T> {
|
||||
protected _enumerator: IEnumerator<T>
|
||||
|
||||
constructor(enumerator: IEnumerator<T>) {
|
||||
this._enumerator = enumerator
|
||||
}
|
||||
|
||||
static from<T>(value: IEnumerable<T> | IEnumerator<T> | Iterable<T> | Iterator<T>): Enumerable<T> {
|
||||
if (this.isEnumerable<T>(value)) {
|
||||
return value
|
||||
} else if (this.isEnumerator<T>(value)) {
|
||||
return new Enumerable(value)
|
||||
} else if (isIterable(value)) {
|
||||
const enumerator = Enumerator.fromIterable(value)
|
||||
|
||||
if (isArrayLike(value)) {
|
||||
return new ArrayEnumerble(enumerator)
|
||||
} else {
|
||||
return new Enumerable(enumerator)
|
||||
}
|
||||
} else if (isIterator(value)) {
|
||||
return new Enumerable(
|
||||
Enumerator.fromIterator(value)
|
||||
)
|
||||
} else {
|
||||
throw new TypeError('value is not enumerable')
|
||||
}
|
||||
}
|
||||
|
||||
static isEnumerable<T>(value: object): value is Enumerable<T> {
|
||||
return typeof value['enumerator'] === 'function'
|
||||
}
|
||||
|
||||
static isEnumerator<T>(value: object): value is IEnumerator<T> {
|
||||
return hasMethods(['moveNext', 'reset', 'toIterator'], value)
|
||||
}
|
||||
|
||||
[Symbol.iterator](): Iterator<T> {
|
||||
return this._enumerator.toIterator()
|
||||
}
|
||||
|
||||
at(index: number): Nullable<T> {
|
||||
while (index >= 0 && this._enumerator.moveNext()) {
|
||||
index -= 1
|
||||
}
|
||||
|
||||
const value = this._enumerator.current
|
||||
this._enumerator.reset()
|
||||
return value
|
||||
}
|
||||
|
||||
atOrDefault(index: number, defaultValue: T) {
|
||||
const value = this.at(index)
|
||||
return value || defaultValue
|
||||
}
|
||||
|
||||
atOrElse(index: number, defaultValue: () => T) {
|
||||
const value = this.at(index)
|
||||
return value || defaultValue()
|
||||
}
|
||||
|
||||
concat(other: IEnumerable<T>): IEnumerable<T> {
|
||||
return new Enumerable(
|
||||
new FusedEnumerator([this._enumerator, other.enumerator()])
|
||||
)
|
||||
}
|
||||
|
||||
drop(limit: number) {
|
||||
return new Enumerable(new DropEnumerator(this._enumerator, limit))
|
||||
}
|
||||
|
||||
enumerator(): IEnumerator<T> {
|
||||
return this._enumerator
|
||||
}
|
||||
|
||||
//entries(): IEnumerator<T> {
|
||||
|
||||
//}
|
||||
|
||||
every(predicate: Predicate<T>): boolean {
|
||||
let index = 0
|
||||
while (this._enumerator.moveNext()) {
|
||||
if (!predicate(this._enumerator.current, index)) {
|
||||
return false
|
||||
}
|
||||
|
||||
index += 1
|
||||
}
|
||||
|
||||
this._enumerator.reset()
|
||||
return true
|
||||
}
|
||||
|
||||
filter(predicate: Predicate<T>): IEnumerable<T> {
|
||||
return new Enumerable(new FilterEnumerator(this._enumerator, predicate))
|
||||
}
|
||||
|
||||
flatMap<U>(fn: Morphism<T, IEnumerator<U>>): IEnumerable<U> {
|
||||
return new Enumerable(new FlatMapEnumerator(this._enumerator, fn))
|
||||
}
|
||||
|
||||
map<U>(fn: Morphism<T, U>): IEnumerable<U> {
|
||||
return new Enumerable(new MapEnumerator(this._enumerator, fn))
|
||||
}
|
||||
|
||||
some(predicate: Predicate<T>): boolean {
|
||||
let index = 0
|
||||
while (this._enumerator.moveNext()) {
|
||||
if (predicate(this._enumerator.current, index)) {
|
||||
return true
|
||||
}
|
||||
|
||||
index += 1
|
||||
}
|
||||
|
||||
this._enumerator.reset()
|
||||
return false
|
||||
}
|
||||
|
||||
take(limit: number): IEnumerable<T> {
|
||||
return new Enumerable(new TakeEnumerator(this._enumerator, limit))
|
||||
}
|
||||
}
|
||||
|
||||
export class ArrayEnumerble<T> extends Enumerable<T> {
|
||||
at(index: number): Nullable<T> {
|
||||
if (this._enumerator instanceof ArrayEnumerator) {
|
||||
this._enumerator.setIndex(index)
|
||||
return this._enumerator.current
|
||||
} else {
|
||||
return super.at(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
7
test/index.js
Executable file
7
test/index.js
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { TerminalRunner } from 'folktest'
|
||||
import * as Tests from './unit/index.js'
|
||||
|
||||
console.log(TerminalRunner(Tests).toString())
|
||||
|
257
test/unit/enumerable.js
Normal file
257
test/unit/enumerable.js
Normal file
|
@ -0,0 +1,257 @@
|
|||
import { it, assert, assertEq, assertErr } from 'folktest'
|
||||
import { ArrayEnumerator, CachedIteratorEnumerator, DropEnumerator, Enumerable, Enumerator, FilterEnumerator, FlatMapEnumerator, FusedEnumerator, IterableEnumerator, IteratorEnumerator, MapEnumerator, TakeEnumerator } from '../../dist/index.js'
|
||||
|
||||
const createIterator = (arr = []) => {
|
||||
let index = 0
|
||||
return {
|
||||
next() {
|
||||
return index < arr.length ? {
|
||||
value: arr[index++],
|
||||
done: false
|
||||
} : { done: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const createIterable = arr => ({
|
||||
[Symbol.iterator]() {
|
||||
return createIterator(arr)
|
||||
}
|
||||
})
|
||||
|
||||
const createEnumerator = arr => Enumerator.fromIterable(createIterable(arr))
|
||||
|
||||
const createEnumerable = arr => Enumerable.from(createIterator(arr))
|
||||
|
||||
const helpers = {
|
||||
concat: {
|
||||
prepare: () => {
|
||||
const e1 = createEnumerable([1, 2, 3])
|
||||
const e2 = createEnumerable([10, 20, 30])
|
||||
return e1.concat(e2)._enumerator
|
||||
},
|
||||
expected: FusedEnumerator
|
||||
},
|
||||
drop: {
|
||||
prepare: () => createEnumerable().drop(0)._enumerator,
|
||||
expected: DropEnumerator
|
||||
},
|
||||
filter: {
|
||||
prepare: () => createEnumerable().filter(x => x)._enumerator,
|
||||
expected: FilterEnumerator
|
||||
},
|
||||
flatMap: {
|
||||
prepare: () => {
|
||||
const e = createEnumerable()
|
||||
return e.flatMap(() => createEnumerator([1]))._enumerator
|
||||
},
|
||||
expected: FlatMapEnumerator
|
||||
},
|
||||
map: {
|
||||
prepare: () => createEnumerable().map(x => x)._enumerator,
|
||||
expected: MapEnumerator
|
||||
},
|
||||
take: {
|
||||
prepare: () => createEnumerable().take(0)._enumerator,
|
||||
expected: TakeEnumerator
|
||||
}
|
||||
}
|
||||
|
||||
export const EnumerableFrom = [
|
||||
it('from iterator', () => {
|
||||
const iterator = createIterator()
|
||||
|
||||
const enumerator = Enumerable.from(iterator)._enumerator
|
||||
assert(enumerator instanceof CachedIteratorEnumerator, `${enumerator.constructor.name} is not an instance of 'CachedIterableEnumerator'`)
|
||||
}),
|
||||
|
||||
it('from iterable', () => {
|
||||
const iterable = createIterable()
|
||||
|
||||
const enumerator = Enumerable.from(iterable)._enumerator._enumerator
|
||||
assert(enumerator instanceof IterableEnumerator, `${enumerator.constructor.name} is not an instance of 'IterableEnumerator'`)
|
||||
}),
|
||||
|
||||
it('from array', () => {
|
||||
const arr = [1, 2, 3]
|
||||
const enumerator = Enumerable.from(arr)._enumerator
|
||||
assert(enumerator instanceof ArrayEnumerator, `${enumerator.constructor.name} is not an instance of 'ArrayBuffer'`)
|
||||
}),
|
||||
|
||||
it('from arraybuffer', () => {
|
||||
const ab = new Uint8Array(1)
|
||||
const enumerator = Enumerable.from(ab)._enumerator
|
||||
assert(enumerator instanceof ArrayEnumerator, `${enumerator.constructor.name} is not an instance of 'ArrayBuffer'`)
|
||||
}),
|
||||
|
||||
it('from enumerator', () => {
|
||||
const iterable = createIterable()
|
||||
|
||||
const enumerator1 = Enumerator.fromIterable(iterable)
|
||||
const enumerable1 = Enumerable.from(enumerator1)
|
||||
assert(enumerable1._enumerator._enumerator instanceof IterableEnumerator, `${enumerable1._enumerator._enumerator.constructor.name} is not an instance of IterableEnumerator`)
|
||||
|
||||
const iterator = createIterator()
|
||||
|
||||
const enumerator2 = Enumerator.fromIterator(iterator, false)
|
||||
const enumerable2 = Enumerable.from(enumerator2)
|
||||
assert(enumerable2._enumerator instanceof IteratorEnumerator, `${enumerable2._enumerator.constructor.name} is not an instance of IteratorEnumerator`)
|
||||
|
||||
const enumerator3 = Enumerator.fromIterator(iterator, true)
|
||||
const enumerable3 = Enumerable.from(enumerator3)
|
||||
assert(enumerable3._enumerator instanceof CachedIteratorEnumerator, `${enumerable3._enumerator.constructor.name} is not an instance of CachedIteratorEnumerator`)
|
||||
}),
|
||||
|
||||
it('from enumerable', () => {
|
||||
const enumerator = {
|
||||
get current() { return undefined },
|
||||
moveNext() { return false },
|
||||
reset() { },
|
||||
}
|
||||
|
||||
const enumerable1 = new Enumerable(enumerator)
|
||||
const enumerable2 = Enumerable.from(enumerable1)
|
||||
assertEq(enumerable1, enumerable2)
|
||||
}),
|
||||
|
||||
it('from invalid should error', () => {
|
||||
const expected = /is not enumerable/g
|
||||
|
||||
assertErr(() => {
|
||||
Enumerable.from(1)
|
||||
}, expected)
|
||||
|
||||
assertErr(() => {
|
||||
Enumerable.from(Symbol())
|
||||
}, expected)
|
||||
})
|
||||
]
|
||||
|
||||
export const EnumerableMethod = [
|
||||
it('at', () => {
|
||||
const arr = [3, 2, 1]
|
||||
const e1 = Enumerable.from(arr)
|
||||
|
||||
const iterator = createIterator(arr)
|
||||
const e2 = Enumerable.from(iterator)
|
||||
|
||||
const iterable = createIterator(arr)
|
||||
const e3 = Enumerable.from(iterable)
|
||||
|
||||
const enums = [e1, e2, e3]
|
||||
|
||||
enums.forEach(e => {
|
||||
arr.forEach((value, index) => {
|
||||
assertEq(e.at(index), value)
|
||||
})
|
||||
})
|
||||
}),
|
||||
|
||||
it('atOrDefault', () => {
|
||||
const arr = [3]
|
||||
const e = Enumerable.from(arr)
|
||||
assertEq(e.atOrDefault(0, 12), 3)
|
||||
assertEq(e.atOrDefault(1, 12), 12)
|
||||
}),
|
||||
|
||||
it('atOrElse', () => {
|
||||
const arr = [3]
|
||||
const e = Enumerable.from(arr)
|
||||
const orElse = () => 12
|
||||
assertEq(e.atOrElse(0, orElse), 3)
|
||||
assertEq(e.atOrElse(1, orElse), 12)
|
||||
}),
|
||||
|
||||
it('enumerator', () => {
|
||||
assert(
|
||||
Enumerable.from([]).enumerator() instanceof ArrayEnumerator
|
||||
)
|
||||
}),
|
||||
|
||||
it('every', () => {
|
||||
const e = Enumerable.from([1, 1, 1])
|
||||
|
||||
assert(e.every(n => Number.isInteger(n)), `${e.toString()}.every failed`)
|
||||
assert(!e.every(n => n > 1), `${e.toString()}.every passed when it should have failed`)
|
||||
}),
|
||||
|
||||
it('enumerator helpers', () => {
|
||||
Object.entries(helpers).forEach(([name, { prepare, expected }]) => {
|
||||
const enumerator = prepare()
|
||||
assert(enumerator instanceof expected, `Enumerable.${name}(): ${enumerator.constructor.name} is not an instance of ${expected.name}`)
|
||||
})
|
||||
}),
|
||||
|
||||
it('some', () => {
|
||||
const e = createEnumerable([1, 2, 3])
|
||||
|
||||
assert(e.some(n => n === 1), `${e.toString()}.some failed`)
|
||||
assert(!e.some(n => n === 4), `${e.toString()}.some passed when it should have failed`)
|
||||
})
|
||||
]
|
||||
|
||||
export const EnumerableHelpers = [
|
||||
it('FusedEnumerator', () => {
|
||||
const expected = [1, 2, 3, 10, 20, 30]
|
||||
const e1 = createEnumerator([1, 2, 3])
|
||||
const e2 = createEnumerator([10, 20, 30])
|
||||
const fe = new FusedEnumerator([e1, e2])
|
||||
expected.forEach(n => {
|
||||
fe.moveNext()
|
||||
assertEq(fe.current, n)
|
||||
})
|
||||
}),
|
||||
|
||||
it('DropEnumerator', () => {
|
||||
const expected = [4, 5, 6]
|
||||
const e = new DropEnumerator(createEnumerator([1, 2, 3, 4, 5, 6]), 3)
|
||||
expected.forEach(n => {
|
||||
e.moveNext()
|
||||
assertEq(e.current, n)
|
||||
})
|
||||
}),
|
||||
|
||||
it('FilterEnumerator', () => {
|
||||
const expected = [1, 3, 5]
|
||||
const e = new FilterEnumerator(createEnumerator([1, 2, 3, 4, 5, 6]), x => x % 2 !== 0)
|
||||
expected.forEach(n => {
|
||||
e.moveNext()
|
||||
assertEq(e.current, n)
|
||||
})
|
||||
}),
|
||||
|
||||
it('FlatMapEnumerator', () => {
|
||||
const expected = [1, 2, 2, 3, 3, 3]
|
||||
const e = new FlatMapEnumerator(
|
||||
createEnumerator([1, 2, 3]),
|
||||
n => {
|
||||
const arr = Array.from({ length: n }).fill(n)
|
||||
return createEnumerator(arr)
|
||||
}
|
||||
)
|
||||
|
||||
expected.forEach(n => {
|
||||
e.moveNext()
|
||||
assertEq(e.current, n)
|
||||
})
|
||||
}),
|
||||
|
||||
it('MapEnumerator', () => {
|
||||
const expected = [1, 4, 9]
|
||||
const e = new MapEnumerator(createEnumerator([1, 2, 3]), n => n * n)
|
||||
expected.forEach(n => {
|
||||
e.moveNext()
|
||||
assertEq(e.current, n)
|
||||
})
|
||||
}),
|
||||
|
||||
it('TakeEnumerator', () => {
|
||||
const expected = [1, 2, 3]
|
||||
const e = new TakeEnumerator(createEnumerator([1, 2, 3, 4, 5, 6]), 3)
|
||||
expected.forEach(n => {
|
||||
e.moveNext()
|
||||
assertEq(e.current, n)
|
||||
})
|
||||
})
|
||||
]
|
||||
|
2
test/unit/index.js
Normal file
2
test/unit/index.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from './enumerable.js'
|
||||
|
Loading…
Add table
Reference in a new issue