This repository has been archived by the owner on Aug 29, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from vunb/typescript
[WIP] Convert to Typescript
- Loading branch information
Showing
23 changed files
with
5,395 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,4 +60,6 @@ typings/ | |
# kites | ||
.vscode | ||
test*.js | ||
*.config.json | ||
*.config.json | ||
dist | ||
cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Development Tools | ||
|
||
* node ^8.11.1 | ||
* npm ^6.0.1 | ||
* yarn ^1.7.0 | ||
* typescript ^3.1.2 | ||
* tslint ^5.11.0 | ||
* ts-node ^7.0.1 | ||
* mocha ^5.2.0 | ||
* chai ^4.2.0 | ||
|
||
# Installation Scripts | ||
|
||
1. npm install -g typescript@latest | ||
2. npm install -g tslint@latest | ||
3. yarn add --dev ts-node tslint typescript typescript-eslint-parser @types/node rimraf | ||
|
||
# Visual Studio Code IDE | ||
|
||
* VS Code 1.25.0 | ||
* EditorConfig for VS Code | ||
* TSLint for VS Code | ||
* GitLens |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { expect } from 'chai'; | ||
import { EventCollectionEmitter, ICollectionItem } from './event-collection'; | ||
|
||
describe('EventCollectionEmitter', () => { | ||
var listeners: EventCollectionEmitter; | ||
beforeEach(() => { | ||
listeners = new EventCollectionEmitter(); | ||
}); | ||
|
||
it('should return a valid awaitable promise', async () => { | ||
listeners.add('test', () => Promise.resolve(1)); | ||
listeners.add('test', () => Promise.resolve(2)); | ||
let result = await listeners.fire(); | ||
expect(result[0]).eq(1); | ||
expect(result[1]).eq(2); | ||
}); | ||
|
||
it('should fire with arguments', async () => { | ||
let obj: any = {}; | ||
listeners.add('test', (o: any) => { | ||
o.ic = 'kites framework'; | ||
return 2.0; | ||
}); | ||
|
||
let [result] = await listeners.fire(obj); | ||
expect(obj.ic).eq('kites framework'); | ||
expect(result).eq(2.0); | ||
}); | ||
|
||
it('should got an error!', async () => { | ||
try { | ||
listeners.add('test', () => Promise.reject('foo')); | ||
await listeners.fire(); | ||
} catch (err) { | ||
expect(err).eq('foo'); | ||
} | ||
}); | ||
|
||
it('should apply pre hooks', async () => { | ||
let i = 0; | ||
let preHookResult; | ||
listeners.pre(function(this: ICollectionItem) { | ||
i++; | ||
preHookResult = this.key; | ||
}); | ||
|
||
listeners.pre(() => { | ||
i++; | ||
}); | ||
|
||
listeners.add('test', () => 100); | ||
|
||
let [result] = await listeners.fire(); | ||
expect(preHookResult).eq('test'); | ||
expect(result).eq(100); | ||
expect(i).eq(2); | ||
}); | ||
|
||
it('should apply post hooks', async () => { | ||
let i = 0; | ||
let postHookResult; | ||
listeners.post(function(this: ICollectionItem) { | ||
i++; | ||
postHookResult = this.key; | ||
}); | ||
|
||
listeners.post(() => { | ||
i += 2; | ||
}); | ||
|
||
listeners.add('post', () => 100); | ||
|
||
let [result] = await listeners.fire(); | ||
expect(postHookResult).eq('post'); | ||
expect(result).eq(100); | ||
expect(i).eq(3); | ||
}); | ||
|
||
it('should apply postError hooks', async () => { | ||
let error; | ||
listeners.postFail((err: Error) => { | ||
error = err; | ||
}); | ||
|
||
listeners.add('test', () => { | ||
return Promise.reject(new Error('foo')); | ||
}); | ||
|
||
try { | ||
await listeners.fire(); | ||
} catch (err) { | ||
expect(err).eq(error); | ||
} | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
export interface ICollectionItem { | ||
readonly key: string; | ||
readonly fn: Function; | ||
readonly context: object|Function; | ||
} | ||
|
||
export class EventCollectionEmitter { | ||
[key: string]: any; | ||
private listeners: ICollectionItem[]; | ||
private preHooks: Function[]; | ||
private postHooks: Function[]; | ||
private postFailHooks: Function[]; | ||
|
||
constructor() { | ||
this.listeners = []; | ||
this.preHooks = []; | ||
this.postHooks = []; | ||
this.postFailHooks = []; | ||
} | ||
|
||
/** | ||
* Add listener callback at the end of the current chain | ||
* @param key | ||
* @param context | ||
* @param listener | ||
*/ | ||
add(key: string, context: Object|Function, listener?: Function) { | ||
let ctx = listener == null ? this : context; | ||
let fn = listener || context as Function; | ||
|
||
if (typeof fn !== 'function') { | ||
throw new Error('Listener must be a function!'); | ||
} | ||
|
||
this.listeners.push({ | ||
context: ctx, | ||
fn: fn, | ||
key: key | ||
}); | ||
} | ||
|
||
/** | ||
* Remove the listener specified by its key from the collection | ||
* @param key | ||
*/ | ||
remove(key: string) { | ||
this.listeners = this.listeners.filter(x => x.key !== key); | ||
} | ||
|
||
/** | ||
* add hook that will be executed before actual listener | ||
* @param fn | ||
*/ | ||
pre(fn: Function) { | ||
this.preHooks.push(fn); | ||
} | ||
|
||
/** | ||
* add hook that will be executed after actual listener | ||
* @param fn | ||
*/ | ||
post(fn: Function) { | ||
this.postHooks.push(fn); | ||
} | ||
|
||
/** | ||
* add hook that will be executed after actual listener when execution will fail | ||
* @param fn | ||
*/ | ||
postFail(fn: Function) { | ||
this.postFailHooks.push(fn); | ||
} | ||
|
||
/** | ||
* Fire registered listeners in sequence and returns a promise containing wrapping an array of all individual results | ||
* The parameters passed to the fire are forwarded in the same order to the listeners | ||
* @returns {Promise<U>} | ||
*/ | ||
async fire(...args: object[]) { | ||
var self: EventCollectionEmitter = this; | ||
|
||
function mapSeries(arr: any[], next: Function) { | ||
// create a empty promise to start our series | ||
var currentPromise = Promise.resolve(); | ||
var promises = arr.map(async (item) => { | ||
// execute the next function after the previous has resolved successfully | ||
return (currentPromise = currentPromise.then(() => next(item))); | ||
}); | ||
// group the results for executing concurrently | ||
// and return the group promise | ||
return Promise.all(promises); | ||
} | ||
|
||
function applyHook(listener: ICollectionItem, hookArrayName: string, outerArgs: any[]) { | ||
var hooks = self[hookArrayName] as Function[]; | ||
hooks.forEach((hook) => { | ||
try { | ||
hook.apply(listener, outerArgs); | ||
} catch (err) { | ||
console.warn('Event listener [' + hookArrayName + '] hook got an error!', err); | ||
} | ||
}); | ||
} | ||
|
||
return await mapSeries(this.listeners, async (listener: ICollectionItem) => { | ||
if (!listener) { | ||
return null; | ||
} | ||
var currentArgs = args.slice(0); | ||
applyHook(listener, 'preHooks', currentArgs); | ||
|
||
try { | ||
let valOrPromise = listener.fn.apply(listener.context, currentArgs); | ||
let result = await Promise.resolve(valOrPromise); | ||
applyHook(listener, 'postHooks', currentArgs); | ||
return result; | ||
} catch (err) { | ||
currentArgs.unshift(err); | ||
// console.warn('Event listener got an error!', err); | ||
applyHook(listener, 'postFailHooks', currentArgs); | ||
return Promise.reject(err); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.