Skip to content

Commit

Permalink
Add lifted functions
Browse files Browse the repository at this point in the history
  • Loading branch information
emonkak committed May 8, 2016
1 parent c7398cd commit a4410b8
Show file tree
Hide file tree
Showing 47 changed files with 507 additions and 63 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc --rootDir src --outDir dist",
"build": "tsc --declaration --rootDir src --outDir dist",
"clean": "rm -fr coverage dist",
"coverage": "isparta cover --include-all-sources --report lcovonly --report html --report text ./node_modules/mocha/bin/_mocha -- --compilers js:babel-core/register",
"lint": "eslint dist",
Expand Down
142 changes: 142 additions & 0 deletions src/Enumerable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import ILiftable from './internal/ILiftable';
import _catch from './static/catch';
import _if from './static/if';
import _return from './static/return';
import concat from './static/concat';
import defer from './static/defer';
import generate from './static/generate';
import range from './static/range';
import repeat from './static/repeat';
import zip from './static/zip';

export default class Enumerable<TSource> implements ILiftable<TSource> {
static catch<TSource>(...sources: Iterable<TSource>[]): Enumerable<TSource> {
return new Enumerable(_catch(...sources));
}

static concat<TSource>(...sources: Iterable<TSource>[]): Enumerable<TSource> {
return new Enumerable(concat(...sources));
}

static defer<TSource>(iterableFactory: () => Iterable<TSource>): Enumerable<TSource> {
return new Enumerable(defer(iterableFactory))
}

static generate<TState, TResult>(initialState: TState, condition: (state: TState) => boolean, iterate: (state: TState) => TState, resultSelector: (state: TState) => TResult): Enumerable<TResult> {
return new Enumerable(generate(initialState, condition, iterate, resultSelector));
}

static if<TResult>(condition: () => boolean, thenSource: Iterable<TResult>, elseSource: Iterable<TResult>): Enumerable<TResult> {
return new Enumerable(_if(condition, thenSource, elseSource));
}

static range(start: number, count: number): Enumerable<number> {
return new Enumerable(range(start, count));
}

static repeat<TSource>(element: TSource, count?: number): Enumerable<TSource> {
return new Enumerable(repeat(element, count));
}

static return<TSource>(element: TSource): Enumerable<TSource> {
return new Enumerable(_return(element));
}

static zip<TFirst, TSecond, TResult>(first: Iterable<TFirst>, second: Iterable<TSecond>, resultSelector: (first: TFirst, second: TSecond) => TResult): Enumerable<TResult> {
return new Enumerable(zip(first, second, resultSelector));
}

constructor(private _source: Iterable<TSource>) {
}

[Symbol.iterator](): Iterator<TSource> {
return this._source[Symbol.iterator]();
}

lift<TResult>(source: Iterable<TResult>): Enumerable<TResult> {
return new Enumerable(source);
}

// Mixins:
aggregate: <TAccumulate>(seed: TAccumulate, func: (result: TAccumulate, element: TSource) => TAccumulate) => TAccumulate;
all: (predicate?: (element: TSource) => boolean) => boolean;
any: (predicate?: (element: TSource) => boolean) => boolean;
average: (selector?: (element: TSource) => number) => number;
buffer: (count: number, skip?: number) => ILiftable<TSource[]>;
catch: <TException>(handler: (exception: TException) => Iterable<TSource>) => ILiftable<TSource>;
concat: (...sources: Iterable<TSource>[]) => ILiftable<TSource>;
count: (predicate?: (item: TSource) => boolean) => number;
defaultIfEmpty: (defaultValue: TSource) => ILiftable<TSource>;
distinct: {
(): ILiftable<TSource>;
<TKey>(keySelector?: (element: TSource) => Iterable<TKey>): ILiftable<TSource>;
};
distinctUntilChanged: {
(): ILiftable<TSource>;
<TSource, TKey>(keySelector?: (element: TSource) => TKey): ILiftable<TSource>;
};
do: (action: (element: TSource) => void) => ILiftable<TSource>;
doWhile: (condition: () => boolean) => ILiftable<TSource>;
elementAt: (index: number) => TSource;
elementAtOrDefault: (index: number, defaultValue?: TSource) => TSource;
except: (second: Iterable<TSource>) => ILiftable<TSource>;
finally: (finallyAction: () => void) => ILiftable<TSource>;
first: (predicate?: (element: TSource) => boolean) => TSource;
firstOrDefault: (predicate?: (element: TSource) => boolean, defaultValue?: TSource) => TSource;
forEach: (action: (element: TSource) => void) => void;
groupBy: {
<TKey>(keySelector: (element: TSource) => TKey): ILiftable<[TKey, TSource]>;
<TKey, TElement>(keySelector: (element: TSource) => TKey, elementSelector: (element: TSource) => TElement): ILiftable<[TKey, TElement]>;
<TKey, TElement, TResult>(keySelector: (element: TSource) => TKey, elementSelector?: (element: TSource) => TElement, resultSelector?: (key: TKey, elements: TElement[]) => TResult): ILiftable<TResult>;
};
groupJoin: <TInner, TKey, TResult>(inner: Iterable<TInner>, outerKeySelector: (element: TSource) => TKey, innerKeySelector: (element: TInner) => TKey, resultSelector: (outer: TSource, inner: TInner[]) => TResult) => ILiftable<TResult>;
ignoreElements: () => ILiftable<TSource>;
intersect: (second: Iterable<TSource>) => ILiftable<TSource>;
isEmpty: () => boolean;
join: <TInner, TKey, TResult>(inner: Iterable<TInner>, outerKeySelector: (element: TSource) => TKey, innerKeySelector: (element: TInner) => TKey, resultSelector: (outer: TSource, inner: TInner) => TResult) => ILiftable<TResult>;
last: (predicate?: (value: TSource) => boolean) => TSource;
lastOrDefault: (predicate?: (value: TSource) => boolean, defaultValue?: TSource) => TSource;
max: (selector: (element: TSource) => number) => number;
maxBy: <TKey>(keySelector: (element: TSource) => TKey) => TSource[];
memoize: () => ILiftable<TSource>;
min: (selector: (element: TSource) => number) => number;
minBy: <TKey>(keySelector: (element: TSource) => TKey) => TSource[];
onErrorResumeNext: (...sources: Iterable<TSource>[]) => ILiftable<TSource>;
orderBy: {
(): ILiftable<TSource>;
<TKey>(keySelector?: (value: TSource) => TKey): ILiftable<TSource>;
};
orderByDescending: {
(): ILiftable<TSource>;
<TKey>(keySelector?: (value: TSource) => TKey): ILiftable<TSource>;
};
repeat: (count?: number) => ILiftable<TSource>;
retry: (retryCount?: number) => ILiftable<TSource>;
reverse: () => ILiftable<TSource>;
scan: <TAccumulate>(seed: TAccumulate, func: (result: TAccumulate, element: TSource) => TAccumulate) => ILiftable<TAccumulate>;
select: <TResult>(selector: (element: TSource) => TResult) => ILiftable<TResult>;
selectMany: <TResult>(collectionSelector: (element: TSource) => ILiftable<TResult>) => ILiftable<TResult>;
single: (predicate?: (element: TSource) => boolean) => TSource;
singleOrDefault: (predicate?: (element: TSource) => boolean, defaultValue?: TSource) => TSource;
skip: (count: number) => ILiftable<TSource>;
skipLast: (count: number) => ILiftable<TSource>;
skipWhile: (predicate: (element: TSource) => boolean) => ILiftable<TSource>;
startWith: (...elements: TSource[]) => ILiftable<TSource>;
sum: (selector?: (element: TSource) => number) => number;
take: (count: number) => ILiftable<TSource>;
takeLast: (count: number) => ILiftable<TSource>;
takeWhile: (predicate: (element: TSource) => boolean) => ILiftable<TSource>;
toArray: () => TSource[];
toLookup: {
<TKey>(keySelector: (element: TSource) => TKey): Map<TKey, TSource[]>;
<TKey, TElement>(keySelector: (element: TSource) => TKey, elementSelector?: (element: TSource) => TElement): Map<TKey, TElement[]>;
};
toMap: {
<TKey>(keySelector: (element: TSource) => TKey): Map<TKey, TSource>;
<TKey, TElement>(keySelector: (element: TSource) => TKey, elementSelector?: (element: TSource) => TElement): Map<TKey, TElement>;
};
union: (second: Iterable<TSource>) => ILiftable<TSource>;
where: (predicate: (item: TSource) => boolean) => ILiftable<TSource>;
while: (condition: () => boolean) => ILiftable<TSource>;
zip: <TSecond, TResult>(second: Iterable<TSecond>, resultSelector: (first: TSource, second: TSecond) => TResult) => ILiftable<TResult>;
}
7 changes: 1 addition & 6 deletions src/groupBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ import toLookup from './toLookup';

export default function groupBy<TSource, TKey>(this: Iterable<TSource>, keySelector: (element: TSource) => TKey): Iterable<[TKey, TSource]>;
export default function groupBy<TSource, TKey, TElement>(this: Iterable<TSource>, keySelector: (element: TSource) => TKey, elementSelector: (element: TSource) => TElement): Iterable<[TKey, TElement]>;
export default function* groupBy<TSource, TKey, TElement, TResult>(
this: Iterable<TSource>,
keySelector: (element: TSource) => TKey,
elementSelector?: (element: TSource) => TElement,
resultSelector?: (key: TKey, elements: TElement[]) => TResult
): Iterable<TResult> {
export default function* groupBy<TSource, TKey, TElement, TResult>(this: Iterable<TSource>, keySelector: (element: TSource) => TKey, elementSelector?: (element: TSource) => TElement, resultSelector?: (key: TKey, elements: TElement[]) => TResult): Iterable<TResult> {
if (elementSelector == null) elementSelector = x => x as any;
if (resultSelector == null) resultSelector = (k, vs) => [k, vs] as any;

Expand Down
16 changes: 5 additions & 11 deletions src/groupJoin.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import toLookup from './toLookup';

export default function* groupJoin<TOuter, TInner, TKey, TResult>(
this: Iterable<TOuter>,
inner: Iterable<TInner>,
outerKeySelector: (element: TOuter) => TKey,
innerKeySelector: (element: TInner) => TKey,
resultSelector: (outer: TOuter, inner: TInner[]) => TResult
): Iterable<TResult> {
export default function* groupJoin<TOuter, TInner, TKey, TResult>(this: Iterable<TOuter>, inner: Iterable<TInner>, outerKeySelector: (element: TOuter) => TKey, innerKeySelector: (element: TInner) => TKey, resultSelector: (outer: TOuter, inner: TInner[]) => TResult): Iterable<TResult> {
const lookup = toLookup.call(inner, innerKeySelector);

for (const element of this) {
const key = outerKeySelector(element);
for (const outerElement of this) {
const key = outerKeySelector(outerElement);
if (lookup.has(key)) {
yield resultSelector(element, lookup.get(key));
yield resultSelector(outerElement, lookup.get(key));
} else {
yield resultSelector(element, []);
yield resultSelector(outerElement, []);
}
}
}
137 changes: 121 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,122 @@
import _catch from './static/catch';
import concat from './static/concat';
import defer from './static/defer';
import generate from './static/generate';
import range from './static/range';
import repeat from './static/repeat';
import zip from './static/zip';
import Enumerable from './Enumerable';
import aggregate from './aggregate';
import all from './all';
import any from './any';
import average from './average';
import buffer from './lifted/buffer';
import _catch from './lifted/catch';
import concat from './lifted/concat';
import count from './count';
import defaultIfEmpty from './lifted/defaultIfEmpty';
import distinct from './lifted/distinct';
import distinctUntilChanged from './lifted/distinctUntilChanged';
import _do from './lifted/do';
import doWhile from './lifted/doWhile';
import elementAt from './elementAt';
import elementAtOrDefault from './elementAtOrDefault';
import except from './lifted/except';
import _finally from './lifted/finally';
import first from './first';
import firstOrDefault from './firstOrDefault';
import forEach from './forEach';
import groupBy from './lifted/groupBy';
import groupJoin from './lifted/groupJoin';
import ignoreElements from './lifted/ignoreElements';
import intersect from './lifted/intersect';
import isEmpty from './isEmpty';
import join from './lifted/join';
import last from './last';
import lastOrDefault from './lastOrDefault';
import max from './max';
import maxBy from './maxBy';
import memoize from './lifted/memoize';
import min from './min';
import minBy from './minBy';
import onErrorResumeNext from './lifted/onErrorResumeNext';
import orderBy from './lifted/orderBy';
import orderByDescending from './lifted/orderByDescending';
import repeat from './lifted/repeat';
import retry from './lifted/retry';
import reverse from './lifted/reverse';
import scan from './lifted/scan';
import select from './lifted/select';
import selectMany from './lifted/selectMany';
import single from './single';
import singleOrDefault from './singleOrDefault';
import skip from './lifted/skip';
import skipLast from './lifted/skipLast';
import skipWhile from './lifted/skipWhile';
import startWith from './lifted/startWith';
import sum from './sum';
import take from './lifted/take';
import takeLast from './lifted/takeLast';
import takeWhile from './lifted/takeWhile';
import toArray from './toArray';
import toLookup from './toLookup';
import toMap from './toMap';
import union from './lifted/union';
import where from './lifted/where';
import _while from './lifted/while';
import zip from './lifted/zip';

export default {
catch: _catch,
concat,
defer,
generate,
range,
repeat,
zip
};
Enumerable.prototype.aggregate = aggregate;
Enumerable.prototype.all = all;
Enumerable.prototype.any = any;
Enumerable.prototype.average = average;
Enumerable.prototype.buffer = buffer;
Enumerable.prototype.catch = _catch;
Enumerable.prototype.concat = concat;
Enumerable.prototype.count = count;
Enumerable.prototype.defaultIfEmpty = defaultIfEmpty;
Enumerable.prototype.distinct = distinct;
Enumerable.prototype.distinctUntilChanged = distinctUntilChanged;
Enumerable.prototype.do = _do;
Enumerable.prototype.doWhile = doWhile;
Enumerable.prototype.elementAt = elementAt;
Enumerable.prototype.elementAtOrDefault = elementAtOrDefault;
Enumerable.prototype.except = except;
Enumerable.prototype.finally = _finally;
Enumerable.prototype.first = first;
Enumerable.prototype.firstOrDefault = firstOrDefault;
Enumerable.prototype.forEach = forEach;
Enumerable.prototype.groupBy = groupBy;
Enumerable.prototype.groupJoin = groupJoin;
Enumerable.prototype.ignoreElements = ignoreElements;
Enumerable.prototype.intersect = intersect;
Enumerable.prototype.isEmpty = isEmpty;
Enumerable.prototype.join = join;
Enumerable.prototype.last = last;
Enumerable.prototype.lastOrDefault = lastOrDefault;
Enumerable.prototype.max = max;
Enumerable.prototype.maxBy = maxBy;
Enumerable.prototype.memoize = memoize;
Enumerable.prototype.min = min;
Enumerable.prototype.minBy = minBy;
Enumerable.prototype.onErrorResumeNext = onErrorResumeNext;
Enumerable.prototype.orderBy = orderBy;
Enumerable.prototype.orderByDescending = orderByDescending;
Enumerable.prototype.repeat = repeat;
Enumerable.prototype.retry = retry;
Enumerable.prototype.reverse = reverse;
Enumerable.prototype.scan = scan;
Enumerable.prototype.select = select;
Enumerable.prototype.selectMany = selectMany;
Enumerable.prototype.single = single;
Enumerable.prototype.singleOrDefault = singleOrDefault;
Enumerable.prototype.skip = skip;
Enumerable.prototype.skipLast = skipLast;
Enumerable.prototype.skipWhile = skipWhile;
Enumerable.prototype.startWith = startWith;
Enumerable.prototype.sum = sum;
Enumerable.prototype.take = take;
Enumerable.prototype.takeLast = takeLast;
Enumerable.prototype.takeWhile = takeWhile;
Enumerable.prototype.toArray = toArray;
Enumerable.prototype.toLookup = toLookup;
Enumerable.prototype.toMap = toMap;
Enumerable.prototype.union = union;
Enumerable.prototype.where = where;
Enumerable.prototype.while = _while;
Enumerable.prototype.zip = zip;

export default Enumerable;
5 changes: 5 additions & 0 deletions src/internal/ILiftable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
interface ILiftable<TSource> extends Iterable<TSource> {
lift<TResult>(source: Iterable<TResult>): ILiftable<TResult>;
}

export default ILiftable;
16 changes: 5 additions & 11 deletions src/join.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import toLookup from './toLookup';

export default function* join<TOuter, TInner, TKey, TResult>(
this: Iterable<TOuter>,
inner: Iterable<TInner>,
outerKeySelector: (element: TOuter) => TKey,
innerKeySelector: (element: TInner) => TKey,
resultSelector: (outer: TOuter, inner: TInner) => TResult
): Iterable<TResult> {
export default function* join<TOuter, TInner, TKey, TResult>(this: Iterable<TOuter>, inner: Iterable<TInner>, outerKeySelector: (element: TOuter) => TKey, innerKeySelector: (element: TInner) => TKey, resultSelector: (outer: TOuter, inner: TInner) => TResult): Iterable<TResult> {
const lookup = toLookup.call(inner, innerKeySelector);

for (const element of this) {
const key = outerKeySelector(element);
for (const outerElement of this) {
const key = outerKeySelector(outerElement);
if (lookup.has(key)) {
for (const inner of lookup.get(key)) {
yield resultSelector(element, inner);
for (const innerElement of lookup.get(key)) {
yield resultSelector(outerElement, innerElement);
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/lifted/buffer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import ILiftable from '../internal/ILiftable';
import bufferFn from '../buffer';

export default function buffer<TSource>(this: ILiftable<TSource>, count: number, skip?: number): ILiftable<TSource> {
return this.lift<TSource>(bufferFn.call(this, count, skip));
}
6 changes: 6 additions & 0 deletions src/lifted/catch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import ILiftable from '../internal/ILiftable';
import catchFn from '../catch';

export default function _catch<TSource, TException>(this: ILiftable<TSource>, handler: (exception: TException) => Iterable<TSource>): ILiftable<TSource> {
return this.lift<TSource>(catchFn.call(this, handler));
}
6 changes: 6 additions & 0 deletions src/lifted/concat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import ILiftable from '../internal/ILiftable';
import concatFn from '../concat';

export default function concat<TSource>(this: ILiftable<TSource>, ...sources: Iterable<TSource>[]): ILiftable<TSource> {
return this.lift<TSource>(concatFn.apply(this, sources));
}
6 changes: 6 additions & 0 deletions src/lifted/defaultIfEmpty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import ILiftable from '../internal/ILiftable';
import defaultIfEmptyFn from '../defaultIfEmpty';

export default function defaultIfEmpty<TSource>(this: ILiftable<TSource>, defaultValue: TSource): ILiftable<TSource> {
return this.lift<TSource>(defaultIfEmptyFn.call(this, defaultValue));
}
7 changes: 7 additions & 0 deletions src/lifted/distinct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import ILiftable from '../internal/ILiftable';
import distinctFn from '../distinct';

export default function distinct<TSource>(this: ILiftable<TSource>): ILiftable<TSource>;
export default function distinct<TSource, TKey>(this: ILiftable<TSource>, keySelector?: (element: TSource) => TKey): ILiftable<TSource> {
return this.lift<TSource>(distinctFn.call(this, keySelector));
}
Loading

0 comments on commit a4410b8

Please sign in to comment.