import { Dictionary, Producer, SequenceIterator, Transform } from "../../types/types" import { Pipe } from "../../types/sequence/pipe" import { OmniSequence } from "../../types/sequence/omni-sequence" import { ErrorMessage } from "../../shared"; /** * Yields all own-property names in an object. */ export function keys(object: Dictionary): OmniSequence { return new Pipe(generateKeys(object)) } /** * Yields all key-value pairs in an object. */ export function pairs(object: Dictionary): OmniSequence<[string, V]> { return new Pipe(generatePairs(object)) } /** * Yields all integers from zero to **end**. Does not include **end**. */ export function range(end: number): OmniSequence /** * Yields all numbers from **start** to **end** with a step size of one. Does not include **end**. Throws an error * if **start** is greater than **end**. */ export function range(start: number, end: number): OmniSequence /** * Yields all numbers from **start** to **end** with a provided **step** size. Does not include **end**. Throws an * error if **start** is greater than **end** or the **step** size is zero. */ export function range(start: number, end: number, step: number): OmniSequence export function range(first: number, second?: number, step: number = 1): OmniSequence { let start, end if (second === undefined) { start = 0 end = first } else { start = first end = second } if (step === 0) { throw Error(ErrorMessage.invalidRangeStep) } if (end < start) { throw Error(ErrorMessage.invalidRangeBounds) } return new Pipe(generateRange(start, end, step)) } /** * Yields the values of all own-properties in an **object**. */ export function values(object: Dictionary): OmniSequence { return new Pipe(generateValues(object)) } /** * Yields an infinite sequence where each element is generated by a **producer** function. */ export function sequence(producer: Producer): OmniSequence /** * Yields an infinite sequence where each element is generated by passing the previous element into the **next** * transform function. The **initial** value will be the first value passed into **next**. */ export function sequence(initial: T, next: Transform): OmniSequence export function sequence(first: T | Producer, second?: Transform): OmniSequence { if (second === undefined) { return new Pipe(generateSequence(undefined, first as Producer)) as OmniSequence } return new Pipe(generateSequence(first as T, second as any)) as OmniSequence } function* generateKeys(object: Dictionary): SequenceIterator { for (let key in object) { if (object.hasOwnProperty(key)) { yield key } } } function* generatePairs(object: Dictionary): SequenceIterator<[string, V]> { for (let key in object) { if (object.hasOwnProperty(key)) { yield [key, object[key]] } } } function* generateRange(start: number, end: number, step: number): SequenceIterator { if (step > 0) { for (let i = start; i < end; i += step) { yield i } } else { for (let i = end + step; i >= start; i += step) { yield i } } } function* generateValues(object: Dictionary): SequenceIterator { for (let key in object) { if (object.hasOwnProperty(key)) { yield object[key] } } } function* generateSequence(initial: T | undefined, next: (current?: T) => T): SequenceIterator { if (initial === undefined) { while (true) { yield next() } } let current = initial while (true) { yield current current = next(current) } }