Skip to content

Commit

Permalink
pkg: add type lints.
Browse files Browse the repository at this point in the history
  • Loading branch information
nodech committed Aug 31, 2023
1 parent 4be1b81 commit bb112cb
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 22 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ jobs:
node-version: 20.x

- name: Install tools
run: npm install --location=global bslint
run: npm install --location=global bslint typescript

- name: Install dependencies
run: npm install

- name: Lint
run: npm run lint

- name: Lint types
run: npm run lint-types

test:
name: Test
runs-on: ${{ matrix.os }}
Expand Down
40 changes: 23 additions & 17 deletions lib/asyncemitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,11 @@ class AsyncEmitter {
/**
* Emit an event synchronously.
* @param {String} type
* @param {...Object} args
* @returns {Promise}
* @param {...any} args
* @returns {void}
*/

emit(type) {
emit(type, ...args) {
try {
this._emit.apply(this, arguments);
} catch (e) {
Expand All @@ -242,7 +242,6 @@ class AsyncEmitter {
* Emit an event synchronously.
* @private
* @param {String} type
* @param {...Object} args
* @returns {Promise}
*/

Expand All @@ -258,9 +257,7 @@ class AsyncEmitter {
if (msg instanceof Error)
throw msg;

const err = new Error(`Uncaught, unspecified "error" event. (${msg})`);
err.context = msg;
throw err;
throw new EmitterError(msg);
}
return;
}
Expand Down Expand Up @@ -313,7 +310,7 @@ class AsyncEmitter {
* @returns {Promise}
*/

async emitAsync(type) {
async emitAsync(type, ...args) {
try {
await this._emitAsync.apply(this, arguments);
} catch (e) {
Expand All @@ -332,7 +329,7 @@ class AsyncEmitter {
* @returns {Promise}
*/

async _emitAsync(type) {
async _emitAsync(type, ...args) {
assert(typeof type === 'string', '`type` must be a string.');

const listeners = this._events[type];
Expand All @@ -344,16 +341,14 @@ class AsyncEmitter {
if (msg instanceof Error)
throw msg;

const err = new Error(`Uncaught, unspecified "error" event. (${msg})`);
err.context = msg;
throw err;
throw new EmitterError(msg);
}
return;
}

assert(listeners.length > 0);

let args = null;
let collectArgs = null;

for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
Expand All @@ -380,18 +375,29 @@ class AsyncEmitter {
await handler(arguments[1], arguments[2], arguments[3]);
break;
default:
if (!args) {
args = new Array(arguments.length - 1);
if (!collectArgs) {
collectArgs = new Array(arguments.length - 1);
for (let j = 1; j < arguments.length; j++)
args[j - 1] = arguments[j];
collectArgs[j - 1] = arguments[j];
}
await handler.apply(null, args);
await handler.apply(null, collectArgs);
break;
}
}
}
}

class EmitterError extends Error {
constructor(msg) {
super(`Uncaught, unspecified "error" event. (${msg})`);
this.type = 'EmitterError';
this.context = msg || '';

if (Error.captureStackTrace)
Error.captureStackTrace(this, EmitterError);
}
}

/**
* Event Listener
* @ignore
Expand Down
9 changes: 8 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
"main": "./lib/bevent.js",
"scripts": {
"lint": "eslint lib/ test/",
"lint-types": "tsc -p .",
"test": "bmocha --reporter spec test/*-test.js"
},
"dependencies": {
"bsert": "~0.0.12"
},
"devDependencies": {
"bmocha": "^2.1.8"
"bmocha": "^2.1.8",
"bts-type-deps": "^0.0.3"
},
"engines": {
"node": ">=8.0.0"
Expand Down
Empty file removed test/.gitkeep
Empty file.
131 changes: 129 additions & 2 deletions test/event-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,139 @@ describe('Event', function() {
const emitter = new AsyncEmitter();

let done = false;
emitter.on('foo', async () => {
let receivedArgs = null;

emitter.on('foo', async (...args) => {
receivedArgs = args;
await new Promise(r => setTimeout(r, 100));
done = true;
});

await emitter.emitAsync('foo');
await emitter.emitAsync('foo', 1, 2, 3);
assert.strictEqual(done, true);
assert.deepStrictEqual(receivedArgs, [1, 2, 3]);
});

it('should not wait for the async listener with normal emit', async () => {
const emitter = new AsyncEmitter();

let done = false;
let receivedArgs = null;

emitter.on('foo', async (...args) => {
receivedArgs = args;
await new Promise(r => setTimeout(r, 100));
done = true;
});

emitter.emit('foo', 1, 2, 3);
assert.strictEqual(done, false);
assert.deepStrictEqual(receivedArgs, [1, 2, 3]);
});

it('should throw with no error listener', () => {
const emitter = new AsyncEmitter();

emitter.on('foo', (err) => {
throw err;
});

const fooErr = new Error('foo');

let err;
try {
emitter.emit('foo', fooErr);
} catch (e) {
err = e;
}

assert(err);
assert.strictEqual(err, fooErr);

err = null;
try {
emitter.emit('foo', 123);
} catch (e) {
err = e;
}

assert(err);
assert.strictEqual(err.context, 123);
});

it('should not throw with error listener', () => {
const emitter = new AsyncEmitter();

let caughErr = null;

emitter.on('error', (err) => {
caughErr = err;
});

emitter.on('foo', (err) => {
throw err;
});

const fooErr = new Error('foo');

emitter.emit('foo', fooErr);
assert.strictEqual(caughErr, fooErr);

emitter.emit('foo', 123);
assert.strictEqual(caughErr, 123);
});

it('should throw from async with no error listener', async () => {
const emitter = new AsyncEmitter();

emitter.on('foo', async (err) => {
await new Promise(r => setTimeout(r, 100));
throw err;
});

const fooErr = new Error('foo');

let err;
try {
await emitter.emitAsync('foo', fooErr);
} catch (e) {
err = e;
}

assert(err);
assert.strictEqual(err, fooErr);

err = null;
try {
await emitter.emitAsync('foo', 123);
} catch (e) {
err = e;
}

assert(err);
assert.strictEqual(err.context, 123);
});

it('should not throw with error listener', async () => {
const emitter = new AsyncEmitter();

let caughErr = null;

emitter.on('error', (err) => {
caughErr = err;
});

emitter.on('foo', async (err) => {
await new Promise(r => setTimeout(r, 100));
throw err;
});

const fooErr = new Error('foo');

await emitter.emitAsync('foo', fooErr);
assert.strictEqual(caughErr, fooErr);

await emitter.emitAsync('foo', 123);
assert.strictEqual(caughErr, 123);
});
});
31 changes: 31 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"include": [
"lib/**/*.js"
],
"compilerOptions": {
"rootDir": ".",
"target": "ES2020",
"lib": [
"ES2020"
],

"noEmit": true,

"allowJs": true,
"checkJs": true,
"maxNodeModuleJsDepth": 10,

"module": "commonjs",
"moduleResolution": "node",
"resolveJsonModule": true,

"stripInternal": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": false,

"typeRoots": [
"node_modules/bts-type-deps/types"
]
}
}

0 comments on commit bb112cb

Please sign in to comment.