diff --git a/package-lock.json b/package-lock.json index 99e5541..57d2580 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1397,9 +1397,9 @@ } }, "@types/jest": { - "version": "25.2.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.2.2.tgz", - "integrity": "sha512-aRctFbG8Pb7DSLzUt/fEtL3q/GKb9mretFuYhRub2J0q6NhzBYbx9HTQzHrWgBNIxYOlxGNVe6Z54cpbUt+Few==", + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.2.3.tgz", + "integrity": "sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw==", "dev": true, "requires": { "jest-diff": "^25.2.1", @@ -10360,9 +10360,9 @@ } }, "rollup": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.10.2.tgz", - "integrity": "sha512-tivFM8UXBlYOUqpBYD3pRktYpZvK/eiCQ190eYlrAyrpE/lzkyG2gbawroNdbwmzyUc7Y4eT297xfzv0BDh9qw==", + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.10.3.tgz", + "integrity": "sha512-Pw4isow3qDZvIozWtEBSZckSxpZgAj11hLijykaO/qZLNq4VGZVZOANBzoWlMabTtg9edQTe3pkLU39PoIkOeg==", "dev": true, "requires": { "fsevents": "~2.1.2" @@ -11348,9 +11348,9 @@ } }, "terser": { - "version": "4.6.13", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.13.tgz", - "integrity": "sha512-wMvqukYgVpQlymbnNbabVZbtM6PN63AzqexpwJL8tbh/mRT9LE5o+ruVduAGL7D6Fpjl+Q+06U5I9Ul82odAhw==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.7.0.tgz", + "integrity": "sha512-Lfb0RiZcjRDXCC3OSHJpEkxJ9Qeqs6mp2v4jf2MHfy8vGERmVDuvjXdd/EnP5Deme5F2yBRBymKmKHCBg2echw==", "dev": true, "requires": { "commander": "^2.20.0", diff --git a/package.json b/package.json index 585da1c..0d4c929 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "devDependencies": { "@rollup/plugin-typescript": "^3.1.1", "@types/fs-extra": "^9.0.0", - "@types/jest": "^25.2.2", + "@types/jest": "^25.2.3", "@types/node": "^14.0.1", "codecov": "^3.7.0", "fast-check": "^1.24.2", @@ -47,10 +47,10 @@ "istanbul": "^0.4.5", "jest": "26.0.1", "jest-junit": "^10.0.0", - "rollup": "^2.10.2", + "rollup": "^2.10.3", "rxjs": "^6.5.4", "semantic-release": "^17.0.7", - "terser": "^4.6.13", + "terser": "^4.7.0", "ts-jest": "^26.0.0", "ts-node": "^8.10.1", "tslint": "^6.1.2", diff --git a/src/list/list.spec.ts b/src/list/list.spec.ts index 4e6b577..855644c 100644 --- a/src/list/list.spec.ts +++ b/src/list/list.spec.ts @@ -1,4 +1,17 @@ import { List } from './list' +import { listFrom } from './list.factory' + +class Animal { + constructor(public name: string) { } +} +class Dog extends Animal { + dogtag!: string + dogyear!: number +} + +class Cat extends Animal { + likesCatnip = true +} describe(List.name, () => { describe('Integers', () => { @@ -169,11 +182,74 @@ describe(List.name, () => { const sut = List.of('test 1', 'test 2', 'test 3') expect(sut.any(a => a.includes('test'))).toEqual(true) + expect(sut.some(a => a.includes('test'))).toEqual(true) }) it('should', () => { const sut = List.of('test 1', 'UGH!', 'test 2', 'test 3') expect(sut.any(a => a.includes('NOTHERE'))).toEqual(false) + expect(sut.some(a => a.includes('NOTHERE'))).toEqual(false) + }) + }) + + describe('take', () => { + it('should ...', () => { + const sut = List.of(1, 2, 3) + + expect(sut.take(3).toArray()).toEqual([1, 2, 3]) + expect(sut.take(2).toArray()).toEqual([1, 2]) + expect(sut.take(1).toArray()).toEqual([1]) + expect(sut.take(0).toArray()).toEqual([]) + }) + }) + + describe('InstanceOf', () => { + it('should filter on instance', () => { + const dog = new Dog('Rex') + const cat = new Cat('Meow') + const sut = List.of(dog, cat) + + expect(sut.ofType(Cat).toArray().length).toEqual(1) + expect(sut.ofType(Cat).toArray()).toEqual([cat]) + expect(sut.ofType(Dog).toArray().length).toEqual(1) + expect(sut.ofType(Dog).toArray()).toEqual([dog]) }) }) + + describe('Drop', () => { + it('should', () => { + const sut = List.of(1, 5, 10, 15, 20).drop(1).drop(1).toArray() + const sut2 = listFrom(sut).drop(2).toArray() + const sut3 = listFrom(sut2).tail().toArray() + + expect(sut).toEqual([10, 15, 20]) + expect(sut2).toEqual([20]) + expect(sut3).toEqual([]) + }) + }) + + // describe('OrderBy', () => { + // it('should order by object', () => { + // const dog1 = new Dog('Atlas') + // const dog2 = new Dog('Zues') + // const sut = List.of(dog1, dog2) + + // expect(sut.orderBy('dogtag').toEqual([])) + // expect(sut.orderBy('name')).toEqual([]) + // }) + + // it('should order by number', () => { + // const sut = List.of(1, 2, 5, 3, 12) + + // expect(sut.orderBy().toEqual([])) + // expect(sut.orderBy()).toEqual([]) + // }) + + // it('should order by string', () => { + // const sut = List.of('abc', 'efg', 'zel', 'lmao') + + // expect(sut.orderBy().toEqual([])) + // expect(sut.orderBy()).toEqual([]) + // }) + // }) }) \ No newline at end of file diff --git a/src/list/list.ts b/src/list/list.ts index 75a31dc..af6121e 100644 --- a/src/list/list.ts +++ b/src/list/list.ts @@ -1,5 +1,6 @@ // Repurposed from this great piece of code: https://gist.github.com/gvergnaud/6e9de8e06ef65e65f18dbd05523c7ca9 // Implements a number of functions from the .NET LINQ library: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.reverse?view=netcore-3.1 +// tslint:disable: no-let /** * A lazily evaluated list with useful extension methods. @@ -40,7 +41,6 @@ export class List { public static range(start: number, end: number, step = 1): List { return new List(function* () { - // tslint:disable-next-line: no-let let i = start while (i <= end) { yield i @@ -66,10 +66,35 @@ export class List { } as any, this.length) } + /** + * Delete the first N elements from a list. + * @param count + */ + public drop(count: number): List { + const generator = this.generator() as any + return new List(function* () { + let next = generator.next() + let n = 1 + + while (!next.done) { + if (n > count) yield next.value + n++ + next = generator.next() + } + } as any, this.length - count) + } + + /** + * Deletes the first element from a list. + * @param count + */ + tail(): List { + return this.drop(1) + } + public scan(fn: (acc: B, val: B) => B, seed: B): List { const generator = this.generator() as any return new List(function* () { - // tslint:disable-next-line: no-let let acc = seed for (const value of generator) { yield acc = fn(acc, value) @@ -114,6 +139,25 @@ export class List { } as any, this.length + toAdd.length) } + /** + * Make a new list containing just the first N elements from an existing list. + * @param count The number of elements to return. + */ + public take(count: number) { + const generator = this.generator() as any + return new List(function* () { + + let next = generator.next() + let n = 0 + + while (!next.done && count > n) { + yield next.value + n++ + next = generator.next() + } + } as any, this.length > count ? count : this.length) + } + /** * Determines whether all elements of a sequence satisfy a condition. */ @@ -133,7 +177,7 @@ export class List { } /** - * Determines whether a sequence contains any elements. + * Determines whether a sequence contains any elements matching the predicate. * @param fn A function to test each element for a condition. */ public any(fn: (val: T) => boolean): boolean { @@ -149,6 +193,34 @@ export class List { return newList.toArray().length >= 1 } + /** + * Determines whether a sequence contains any elements matching the predicate. + * @param fn A function to test each element for a condition. + * Aliased to any() + */ + public some(fn: (val: T) => boolean): boolean { + return this.any(fn) + } + + /** + * Filters the elements of the list based on a specified type. + * @param type The type to filter the elements of the sequence on. + */ + public ofType(type: Function): List { + return this.filter(a => a instanceof type) + } + + // /** + // * Sorts the elements of a sequence in ascending order. + // */ + // public orderBy(prop?: T extends object ? K : never): List { + // throw Error('Not Implemented') + // } + + // public orderByDescending(): List { + // throw Error('Not Implemented') + // } + /** * Inverts the order of the elements in a sequence. */ @@ -196,7 +268,7 @@ export class List { return [...this as any] as T[] } - /** Convert to standard array. Alias of toArray() */ + /** Convert to standard array. Aliased to toArray() */ public toIterable(): Iterable { return this.toArray() }