Skip to content
This repository has been archived by the owner on Aug 29, 2019. It is now read-only.

Commit

Permalink
Merge pull request #3 from vunb/typescript
Browse files Browse the repository at this point in the history
[WIP] Convert to Typescript
  • Loading branch information
vunb committed Oct 17, 2018
2 parents 7873c4b + 62d3976 commit 027df1d
Show file tree
Hide file tree
Showing 23 changed files with 5,395 additions and 6 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ max_line_length = null
indent_style = space
indent_size = 4

[*.ts]
indent_style = space
indent_size = 4

# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ typings/
# kites
.vscode
test*.js
*.config.json
*.config.json
dist
cache
23 changes: 23 additions & 0 deletions DEVTOOL.md
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
36 changes: 31 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
{
"name": "@kites/engine",
"displayName": "kites",
"version": "0.1.5",
"version": "1.0.0",
"description": "Core Engine of Kites",
"main": "index.js",
"main": "dist/src/main.js",
"scripts": {
"test": "node test | tap-spec"
"build": "tsc && npm run lint",
"clean": "rimraf ./dist",
"lint": "tslint -c tslint.json 'src/**/*.ts'",
"tsc": "tsc",
"test": "mocha -r ts-node/register src/**/*.spec.ts",
"premajor": "release-it premajor --preReleaseId=beta --npm.tag=beta --github.preRelease --verbose",
"release-patch": "release-it",
"release-minor": "release-it minor",
"release-beta": "release-it major --preRelease=beta"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -34,13 +42,31 @@
"winston": "^2.4.0"
},
"devDependencies": {
"@types/app-root-path": "^1.2.4",
"@types/bluebird": "^3.5.24",
"@types/chai": "^4.1.6",
"@types/debug": "^0.0.31",
"@types/lodash": "^4.14.117",
"@types/mkdirp": "^0.5.2",
"@types/mocha": "^5.2.5",
"@types/nconf": "^0.0.37",
"@types/node": "^10.11.7",
"@types/std-mocks": "^1.0.0",
"chai": "^4.2.0",
"mocha": "^5.2.0",
"release-it": "^7.6.1",
"rimraf": "^2.6.2",
"std-mocks": "^1.0.1",
"supertest": "^2.0.1",
"tap-spec": "^4.1.1",
"tape": "^4.6.3"
"tape": "^4.6.3",
"ts-node": "^7.0.1",
"tslint": "^5.11.0",
"typescript": "^3.1.2",
"typescript-eslint-parser": "^20.0.0"
},
"files": [
"engine",
"dist",
"index.js"
]
}
95 changes: 95 additions & 0 deletions src/engine/event-collection.spec.ts
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);
}
});
});
125 changes: 125 additions & 0 deletions src/engine/event-collection.ts
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);
}
});
}
}
Loading

0 comments on commit 027df1d

Please sign in to comment.