Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object inspection creators #35

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"watch": "jest --watch --notify",
"coverage": "rimraf coverage && jest --coverage",
"travis": "yarn lint && yarn test",
"lint": "node_modules/.bin/tslint -c tslint.json 'src/**/*.ts' 'test/**/*.ts'",
"lint": "node_modules/.bin/tslint --fix -c tslint.json 'src/**/*.ts' 'test/**/*.ts'",
"docs": "rimraf docs && typedoc --name Sequency --readme APIDOC.md -out docs --hideGenerator src/Sequence.ts",
"docs-publish": "yarn docs && touch docs/.nojekyll && gh-pages -d docs -t",
"bundle": "webpack --mode production && size-limit",
Expand Down Expand Up @@ -83,4 +83,4 @@
"map",
"set"
]
}
}
188 changes: 118 additions & 70 deletions src/Sequence.ts
Original file line number Diff line number Diff line change
@@ -1,73 +1,73 @@
import {All} from "./all";
import {Any} from "./any";
import {AsIterable} from "./asIterable";
import {Associate} from "./associate";
import {AssociateBy} from "./associateBy";
import {Average} from "./average";
import {Chunk} from "./chunk";
import {Contains} from "./contains";
import {Count} from "./count";
import {Distinct} from "./distinct";
import {DistinctBy} from "./distinctBy";
import {Drop} from "./drop";
import {DropWhile} from "./dropWhile";
import {ElementAt} from "./elementAt";
import {ElementAtOrElse} from "./elementAtOrElse";
import {ElementAtOrNull} from "./elementAtOrNull";
import {Filter} from "./filter";
import {FilterIndexed} from "./filterIndexed";
import {FilterNot} from "./filterNot";
import {FilterNotNull} from "./filterNotNull";
import {First} from "./first";
import {FirstOrNull} from "./firstOrNull";
import {FlatMap} from "./flatMap";
import {Flatten} from "./flatten";
import {Fold} from "./fold";
import {FoldIndexed} from "./foldIndexed";
import {ForEach} from "./forEach";
import {ForEachIndexed} from "./forEachIndexed";
import {GroupBy} from "./groupBy";
import {IndexOf} from "./indexOf";
import {IndexOfFirst} from "./indexOfFirst";
import {IndexOfLast} from "./indexOfLast";
import {JoinToString} from "./joinToString";
import {Last} from "./last";
import {LastOrNull} from "./lastOrNull";
import {Map} from "./map";
import {MapIndexed} from "./mapIndexed";
import {MapNotNull} from "./mapNotNull";
import {Max} from "./max";
import {MaxBy} from "./maxBy";
import {MaxWith} from "./maxWith";
import {Merge} from "./merge";
import {Min} from "./min";
import {MinBy} from "./minBy";
import {Minus} from "./minus";
import {MinWith} from "./minWith";
import {None} from "./none";
import {OnEach} from "./onEach";
import {Partition} from "./partition";
import {Plus} from "./plus";
import {Reduce} from "./reduce";
import {ReduceIndexed} from "./reduceIndexed";
import {Reverse} from "./reverse";
import {Single} from "./single";
import {SingleOrNull} from "./singleOrNull";
import {Sorted} from "./sorted";
import {SortedBy} from "./sortedBy";
import {SortedByDescending} from "./sortedByDescending";
import {SortedDescending} from "./sortedDescending";
import {SortedWith} from "./sortedWith";
import {Sum} from "./sum";
import {SumBy} from "./sumBy";
import {Take} from "./take";
import {TakeWhile} from "./takeWhile";
import {ToArray} from "./toArray";
import {ToMap} from "./toMap";
import {ToSet} from "./toSet";
import {Unzip} from "./unzip";
import {WithIndex} from "./withIndex";
import {Zip} from "./zip";
import { All } from "./all";
import { Any } from "./any";
import { AsIterable } from "./asIterable";
import { Associate } from "./associate";
import { AssociateBy } from "./associateBy";
import { Average } from "./average";
import { Chunk } from "./chunk";
import { Contains } from "./contains";
import { Count } from "./count";
import { Distinct } from "./distinct";
import { DistinctBy } from "./distinctBy";
import { Drop } from "./drop";
import { DropWhile } from "./dropWhile";
import { ElementAt } from "./elementAt";
import { ElementAtOrElse } from "./elementAtOrElse";
import { ElementAtOrNull } from "./elementAtOrNull";
import { Filter } from "./filter";
import { FilterIndexed } from "./filterIndexed";
import { FilterNot } from "./filterNot";
import { FilterNotNull } from "./filterNotNull";
import { First } from "./first";
import { FirstOrNull } from "./firstOrNull";
import { FlatMap } from "./flatMap";
import { Flatten } from "./flatten";
import { Fold } from "./fold";
import { FoldIndexed } from "./foldIndexed";
import { ForEach } from "./forEach";
import { ForEachIndexed } from "./forEachIndexed";
import { GroupBy } from "./groupBy";
import { IndexOf } from "./indexOf";
import { IndexOfFirst } from "./indexOfFirst";
import { IndexOfLast } from "./indexOfLast";
import { JoinToString } from "./joinToString";
import { Last } from "./last";
import { LastOrNull } from "./lastOrNull";
import { Map } from "./map";
import { MapIndexed } from "./mapIndexed";
import { MapNotNull } from "./mapNotNull";
import { Max } from "./max";
import { MaxBy } from "./maxBy";
import { MaxWith } from "./maxWith";
import { Merge } from "./merge";
import { Min } from "./min";
import { MinBy } from "./minBy";
import { Minus } from "./minus";
import { MinWith } from "./minWith";
import { None } from "./none";
import { OnEach } from "./onEach";
import { Partition } from "./partition";
import { Plus } from "./plus";
import { Reduce } from "./reduce";
import { ReduceIndexed } from "./reduceIndexed";
import { Reverse } from "./reverse";
import { Single } from "./single";
import { SingleOrNull } from "./singleOrNull";
import { Sorted } from "./sorted";
import { SortedBy } from "./sortedBy";
import { SortedByDescending } from "./sortedByDescending";
import { SortedDescending } from "./sortedDescending";
import { SortedWith } from "./sortedWith";
import { Sum } from "./sum";
import { SumBy } from "./sumBy";
import { Take } from "./take";
import { TakeWhile } from "./takeWhile";
import { ToArray } from "./toArray";
import { ToMap } from "./toMap";
import { ToSet } from "./toSet";
import { Unzip } from "./unzip";
import { WithIndex } from "./withIndex";
import { Zip } from "./zip";
import GeneratorIterator from "./GeneratorIterator";
import GeneratorSeedIterator from "./GeneratorSeedIterator";

Expand Down Expand Up @@ -174,3 +174,51 @@ export function range(start: number, endInclusive: number, step: number = 1): Se
}
});
}

export function asKeysSequence<K>(keyedIterable: {
keys(): Iterable<K>;
}): Sequence<K>;
export function asKeysSequence<K extends PropertyKey>(obj: Record<K, any>): Sequence<K>;
export function asKeysSequence<K>(a: any): Sequence<K> {
if (typeof a !== "object") {
throw new TypeError("Cannot create keys sequence for non-object input");
}

if (a === null) {
throw new TypeError("Cannot create keys sequence for input: null");
}

const gen = typeof a.keys === "function" ? a.keys.bind(a) : function* () {
for (const key in a) {
if (a.hasOwnProperty(key)) {
yield key as K;
}
}
};

return asSequence(gen());
}

export function asValuesSequence<V>(keyedIterable: {
values(): Iterable<V>;
}): Sequence<V>;
export function asValuesSequence<V>(obj: Record<any, V>): Sequence<V>;
export function asValuesSequence<V>(a: any): Sequence<V> {
if (typeof a !== "object") {
throw new TypeError("Cannot create values sequence for non-object input");
}

if (a === null) {
throw new TypeError("Cannot create values sequence for input: null");
}

const gen = typeof a.values === "function" ? a.values.bind(a) : function* () {
for (const key in a) {
if (a.hasOwnProperty(key)) {
yield a[key];
}
}
};

return asSequence(gen());
}
79 changes: 79 additions & 0 deletions test/asKeysSequence.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { asKeysSequence } from "../src/Sequence";

describe("asKeysSequence", () => {
it("should create sequence from object keys", () => {
const array = asKeysSequence({ "a": 1, "b": 2, "c": 3 } as const)
.toArray();

expect(array.length).toBe(3);
expect(array[0]).toBe("a");
expect(array[1]).toBe("b");
expect(array[2]).toBe("c");
});

it("should create sequence from Map keys", () => {
const array = asKeysSequence(new Map([
["a", 1],
["b", 2],
["c", 3]
] as const))
.toArray();

expect(array.length).toBe(3);
expect(array[0]).toBe("a");
expect(array[1]).toBe("b");
expect(array[2]).toBe("c");
});

it("should create sequence from Set values", () => {
const array = asKeysSequence(new Set([
"a",
"b",
"c"
] as const))
.toArray();

expect(array.length).toBe(3);
expect(array[0]).toBe("a");
expect(array[1]).toBe("b");
expect(array[2]).toBe("c");
});

it("should create sequence from array indexes", () => {
const array = asKeysSequence([
"a",
"b",
"c"
] as const)
.toArray();

expect(array.length).toBe(3);
expect(array[0]).toBe(0);
expect(array[1]).toBe(1);
expect(array[2]).toBe(2);
});

it("should throw understandable error message if input is null", () => {
expect(
() => asKeysSequence(null as any)
).toThrowError("Cannot create keys sequence for input: null");
});

it.each([
{ input: undefined },
{ input: false },
{ input: true },
{ input: 0 },
{ input: 1 },
{ input: 42 },
{ input: 23.42 },
{ input: NaN },
{ input: Infinity },
{ input: () => 42 },
{ input: function* () { yield 42; } }
])("should throw understandable error message if input is non-object: %p", ({ input }) => {
expect(
() => asKeysSequence(input as any)
).toThrowError("Cannot create keys sequence for non-object input");
});
});
79 changes: 79 additions & 0 deletions test/asValuesSequence.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { asValuesSequence } from "../src/Sequence";

describe("asValuesSequence", () => {
it("should create sequence from object values", () => {
const array = asValuesSequence({ "a": 1, "b": 2, "c": 3 } as const)
.toArray();

expect(array.length).toBe(3);
expect(array[0]).toBe(1);
expect(array[1]).toBe(2);
expect(array[2]).toBe(3);
});

it("should create sequence from Map values", () => {
const array = asValuesSequence(new Map([
["a", 1],
["b", 2],
["c", 3]
] as const))
.toArray();

expect(array.length).toBe(3);
expect(array[0]).toBe(1);
expect(array[1]).toBe(2);
expect(array[2]).toBe(3);
});

it("should create sequence from Set values", () => {
const array = asValuesSequence(new Set([
"a",
"b",
"c"
] as const))
.toArray();

expect(array.length).toBe(3);
expect(array[0]).toBe("a");
expect(array[1]).toBe("b");
expect(array[2]).toBe("c");
});

it("should create sequence from array values", () => {
const array = asValuesSequence([
"a",
"b",
"c"
] as const)
.toArray();

expect(array.length).toBe(3);
expect(array[0]).toBe("a");
expect(array[1]).toBe("b");
expect(array[2]).toBe("c");
});

it("should throw understandable error message if input is null", () => {
expect(
() => asValuesSequence(null as any)
).toThrowError("Cannot create values sequence for input: null");
});

it.each([
{ input: undefined },
{ input: false },
{ input: true },
{ input: 0 },
{ input: 1 },
{ input: 42 },
{ input: 23.42 },
{ input: NaN },
{ input: Infinity },
{ input: () => 42 },
{ input: function* () { yield 42; } }
])("should throw understandable error message if input is non-object: %p", ({ input }) => {
expect(
() => asValuesSequence(input as any)
).toThrowError("Cannot create values sequence for non-object input");
});
});