iterize
Version:
Use JavaScript Iterator, Easily
135 lines (108 loc) • 3.26 kB
text/typescript
import {BehaviorError} from './ErrorModels';
import { IterableProtocol } from './types';
export class PrimitiveIterator implements IterableProtocol {
value: number | string | Function;
done: boolean = false;
constructor(value: number | string | Function) {
this.value = value;
}
[Symbol.iterator]() {
return this;
}
public next(value?: any): IteratorResult<any> {
if (this.done) {
return {value: undefined, done: true};
}
this.done = true;
return {value: this.value, done: false};
}
public clone(): IterableProtocol {
return new PrimitiveIterator(this.value);
}
}
export class ArrayIterator implements IterableProtocol {
arr: Array<any>;
arrIterator: Iterator<any>;
// parameter array should be immutable
constructor(arr: Array<any>) {
this.arr = arr;
this.arrIterator = arr[Symbol.iterator]();
}
[Symbol.iterator]() {
return this;
}
public next(value?: any): IteratorResult<any> {
return this.arrIterator.next();
}
public clone(): IterableProtocol {
return new ArrayIterator(this.arr);
}
}
export class RepeatIterator implements IterableProtocol {
static FOREVER: number = -1;
iterator: IterableProtocol;
repeatLimit: number;
repeatCount: number = 1;
constructor(iterator: IterableProtocol, repeatLimit: number) {
this.iterator = iterator;
this.repeatLimit = repeatLimit;
}
[Symbol.iterator]() {
return this;
}
public next(value?: any): IteratorResult<any> {
let next: IteratorResult<any> = this.iterator.next();
if (!next.done) {
return next;
}
if (
this.repeatLimit !== RepeatIterator.FOREVER &&
!(this.repeatCount < this.repeatLimit)
) {
return {value: undefined, done: true};
}
this.iterator = this.iterator.clone();
next = this.iterator.next();
if (next.done) {
throw new BehaviorError('Iterator should iterable more than once.');
}
this.repeatCount++;
return next;
}
public clone(): IterableProtocol {
return new RepeatIterator(this.iterator, this.repeatLimit);
}
}
export class RangeIterator implements IterableProtocol {
start: number;
end: number;
step: Function;
current: number;
constructor(start: number, end: number, step: Function) {
this.start = start;
this.end = end;
this.step = step;
this.current = start;
}
[Symbol.iterator]() {
return this;
}
public next(value?: any): IteratorResult<any> {
if (this.hasNext()) {
let value = this.current;
this.current = this.step(this.current);
return {value: value, done: false};
}
return {value: undefined, done: true};
}
hasNext() {
if (this.start < this.end) {
return this.current < this.end;
} else {
return this.current > this.end;
}
}
public clone(): IterableProtocol {
return new RangeIterator(this.start, this.end, this.step);
}
}