Skip to content

Commit 2f20a26

Browse files
committed
[add] Test Script based on Jest
[add] Building scripts [fix] Several details
1 parent c5df1f1 commit 2f20a26

File tree

10 files changed

+120
-138
lines changed

10 files changed

+120
-138
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules/
22
package-lock.json
33
dist/
4+
.rts2_cache_*/
45
docs/

ReadMe.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,30 @@
22

33
[Observable Proposal][1] implement based on [Async Generator (ES 2018)][2] & [TypeScript][3]
44

5+
## Usage
6+
7+
```javascript
8+
import { Observable } from 'waterwheel';
9+
10+
var count = 0,
11+
list = [];
12+
13+
const observable = new Observable(({ next, complete }: Observer) => {
14+
const timer = setInterval(
15+
() => (++count < 5 ? next(count) : complete(count)),
16+
0
17+
);
18+
19+
return () => clearInterval(timer);
20+
});
21+
22+
(async () => {
23+
for await (const item of observable) list.push(item);
24+
25+
console.log(list); // [1, 2, 3, 4, 5]
26+
})();
27+
```
28+
529
[1]: https://github.com/tc39/proposal-observable
630
[2]: https://tc39.es/ecma262/#sec-asyncgeneratorfunction-objects
731
[3]: https://www.typescriptlang.org/

package.json

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "WaterWheel",
3-
"version": "1.0.0-alpha.0",
2+
"name": "waterwheel",
3+
"version": "1.0.0-alpha.1",
44
"license": "LGPL-3.0",
55
"author": "[email protected]",
66
"description": "Observable Proposal implement based on Async Generator (ES 2018) & TypeScript",
@@ -21,11 +21,21 @@
2121
"bugs": {
2222
"url": "https://github.com/EasyWebApp/WaterWheel/issues"
2323
},
24-
"main": "dist/index.js",
24+
"source": "source/index.ts",
25+
"types": "dist/index.d.ts",
26+
"main": "dist/waterwheel.umd.js",
27+
"module": "dist/waterwheel.js",
2528
"devDependencies": {
29+
"@types/jest": "^24.0.23",
2630
"husky": "^3.0.9",
31+
"jest": "^24.9.0",
2732
"lint-staged": "^9.4.3",
28-
"prettier": "^1.19.1"
33+
"microbundle": "^0.11.0",
34+
"open-cli": "^5.0.0",
35+
"prettier": "^1.19.1",
36+
"ts-jest": "^24.2.0",
37+
"typedoc": "^0.15.2",
38+
"typescript": "^3.7.2"
2939
},
3040
"prettier": {
3141
"singleQuote": true,
@@ -37,12 +47,28 @@
3747
"git add"
3848
]
3949
},
50+
"jest": {
51+
"preset": "ts-jest",
52+
"testEnvironment": "node",
53+
"testRegex": "/test/.*\\.(test|spec)?\\.ts$",
54+
"moduleFileExtensions": [
55+
"js",
56+
"ts",
57+
"json"
58+
]
59+
},
4060
"scripts": {
41-
"test": "lint-staged"
61+
"test": "lint-staged && jest",
62+
"debug": "node --inspect node_modules/jest/bin/jest --runInBand",
63+
"pack-docs": "typedoc --name WaterWheel --out docs/ source/",
64+
"build": "microbundle && npm run pack-docs",
65+
"help": "npm run pack-docs && open-cli docs/index.html",
66+
"prepublishOnly": "npm test && npm run build"
4267
},
4368
"husky": {
4469
"hooks": {
45-
"pre-commit": "npm test"
70+
"pre-commit": "npm test",
71+
"pre-push": "npm run build"
4672
}
4773
}
4874
}

source/Observable.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,44 @@
11
import { Defer, makeDefer } from './utility';
22

3-
export interface Observer {
4-
next(value: any): void;
3+
export interface Observer<T = any> {
4+
next(value: T): void;
55
error(reason: string | Error): void;
6-
complete(value: any): void;
6+
complete(value: T): void;
77
}
88

9-
export type SubscriberFunction = (observer: Observer) => () => void;
9+
export type SubscriberFunction = (observer: Observer) => (() => void) | void;
1010

11-
export default class Observable {
11+
export class Observable<T = any> {
1212
private subscriber: SubscriberFunction;
1313

1414
constructor(subscriber: SubscriberFunction) {
1515
this.subscriber = subscriber;
1616
}
1717

1818
async *[Symbol.asyncIterator]() {
19-
var queue: Defer[] = [makeDefer()],
20-
cursor = 0,
21-
canceler: () => void,
19+
var queue: Defer<T>[] = [makeDefer<T>()],
20+
canceler: (() => void) | void,
2221
done = false;
2322

24-
const observer: Observer = {
23+
const observer: Observer<T> = {
2524
next(value) {
2625
if (done) return;
2726

28-
queue[cursor++].resolve(value);
27+
queue[queue.length - 1].resolve(value);
2928

3029
queue.push(makeDefer());
3130
},
3231
error(reason) {
3332
if (done) return;
3433

35-
queue[cursor].reject(reason), (done = true);
34+
queue[queue.length - 1].reject(reason), (done = true);
3635

3736
if (canceler) canceler();
3837
},
3938
complete(value) {
4039
if (done) return;
4140

42-
queue[cursor++].resolve(value), (done = true);
41+
queue[queue.length - 1].resolve(value), (done = true);
4342

4443
if (canceler) canceler();
4544
}
@@ -48,10 +47,11 @@ export default class Observable {
4847
canceler = this.subscriber(observer);
4948

5049
while (true) {
51-
if (!done) yield queue[0].promise;
52-
else return queue[0].promise;
50+
yield queue[0].promise;
5351

54-
queue.shift(), cursor--;
52+
queue.shift();
53+
54+
if (done) break;
5555
}
5656
}
5757
}

source/utility.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export interface Defer<T = any> {
22
promise: Promise<T>;
3-
resolve: (data: any) => void;
3+
resolve: (data: T) => void;
44
reject: (error: Error | string) => void;
55
}
66

test/index.html

Lines changed: 0 additions & 12 deletions
This file was deleted.

test/index.js

Lines changed: 0 additions & 97 deletions
This file was deleted.

test/index.spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Observable, Observer } from '../source';
2+
3+
describe('Observable', () => {
4+
var observable: Observable, timer: any;
5+
6+
const cleaner = jest.fn(() => clearInterval(timer));
7+
8+
it('should not call Subscriber Function while constructing', () => {
9+
var count = 0;
10+
11+
const subscriber = jest.fn(({ next, complete }: Observer) => {
12+
timer = setInterval(
13+
() => (++count < 5 ? next(count) : complete(count)),
14+
0
15+
);
16+
17+
return cleaner;
18+
});
19+
20+
observable = new Observable<number>(subscriber);
21+
22+
expect(subscriber).toBeCalledTimes(0);
23+
});
24+
25+
it('should iterate Limited items asynchronously', async () => {
26+
const list = [];
27+
28+
for await (const item of observable) list.push(item);
29+
30+
expect(list).toEqual(expect.arrayContaining([1, 2, 3, 4, 5]));
31+
32+
expect(cleaner).toBeCalledTimes(1);
33+
});
34+
35+
it('should throw Error after error() called', () => {
36+
const observable = new Observable(({ error }) => {
37+
error(new Error('test'));
38+
});
39+
40+
expect(
41+
(async () => {
42+
for await (const item of observable);
43+
})()
44+
).rejects.toStrictEqual(new Error('test'));
45+
});
46+
});

test/mocha.opts

Lines changed: 0 additions & 6 deletions
This file was deleted.

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"compilerOptions": {
3-
"module": "umd",
3+
"module": "es6",
44
"moduleResolution": "node",
55
"esModuleInterop": true,
66
"target": "es5",

0 commit comments

Comments
 (0)