Skip to content

Commit

Permalink
feat: merge Ready and EventEmitter (#5)
Browse files Browse the repository at this point in the history
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
	- Added support for Node.js version 22 in CI workflows.
- Introduced a new `ReadyEventEmitter` class for event-driven readiness
handling.
	- Added `ReadyEventClass` to manage 'ready-event' emissions.
- Enhanced documentation with a new badge for Node.js version and a
section on `ReadyEventEmitter`.

- **Bug Fixes**
- Improved promise handling and method documentation in the `Ready`
class.

- **Chores**
- Updated dependency versions in `package.json` and removed unnecessary
dependencies.
	- Removed explicit test check during the release job in CI workflows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
fengmk2 authored Dec 15, 2024
1 parent 405d3c0 commit bb049ea
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 27 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: CI
on:
push:
branches: [ master ]

pull_request:
branches: [ master ]

Expand All @@ -12,5 +11,7 @@ jobs:
name: Node.js
uses: node-modules/github-actions/.github/workflows/node-test.yml@master
with:
version: '16.17.0, 16, 18, 20'
version: '16.17.0, 16, 18, 20, 22'
os: 'ubuntu-latest'
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
2 changes: 0 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,3 @@ jobs:
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
with:
checkTest: false
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[![CI](https://github.com/node-modules/get-ready/actions/workflows/nodejs.yml/badge.svg)](https://github.com/node-modules/get-ready/actions/workflows/nodejs.yml)
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url]
[![Node.js Version](https://img.shields.io/node/v/get-ready.svg?style=flat)](https://nodejs.org/en/download/)

[npm-image]: https://img.shields.io/npm/v/get-ready.svg?style=flat-square
[npm-url]: https://npmjs.org/package/get-ready
Expand Down Expand Up @@ -51,6 +52,16 @@ obj.ready(true);
obj.ready().then(() => console.log('ready'));
```

### ReadyEventEmitter

```ts
import { ReadyEventEmitter } from 'get-ready';

class MyClass extends ReadyEventEmitter {
// your handler here
}
```

**Warning: the callback is called after nextTick**

### Emit
Expand Down Expand Up @@ -79,13 +90,8 @@ obj.ready(new Error('err'));

[MIT](LICENSE)

<!-- GITCONTRIBUTOR_START -->

## Contributors

|[<img src="https://avatars.githubusercontent.com/u/221826?v=4" width="100px;"/><br/><sub><b>supershabam</b></sub>](https://github.com/supershabam)<br/>|[<img src="https://avatars.githubusercontent.com/u/156269?v=4" width="100px;"/><br/><sub><b>fengmk2</b></sub>](https://github.com/fengmk2)<br/>|[<img src="https://avatars.githubusercontent.com/u/360661?v=4" width="100px;"/><br/><sub><b>popomore</b></sub>](https://github.com/popomore)<br/>|[<img src="https://avatars.githubusercontent.com/u/985607?v=4" width="100px;"/><br/><sub><b>dead-horse</b></sub>](https://github.com/dead-horse)<br/>|[<img src="https://avatars.githubusercontent.com/u/32174276?v=4" width="100px;"/><br/><sub><b>semantic-release-bot</b></sub>](https://github.com/semantic-release-bot)<br/>|
| :---: | :---: | :---: | :---: | :---: |

This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Mon Jun 05 2023 14:06:50 GMT+0800`.
[![Contributors](https://contrib.rocks/image?repo=node-modules/get-ready)](https://github.com/node-modules/get-ready/graphs/contributors)

<!-- GITCONTRIBUTOR_END -->
Made with [contributors-img](https://contrib.rocks).
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@
"egg-bin": "^6.4.1",
"eslint": "^8.51.0",
"eslint-config-egg": "^13.0.0",
"git-contributor": "^2.1.5",
"tshy": "^1.2.2",
"tshy": "3",
"tshy-after": "^1.0.0",
"typescript": "^5.2.2"
},
"engines": {
"node": ">= 16.13.0"
},
"scripts": {
"contributor": "git-contributor",
"lint": "eslint src test --ext ts",
"test": "npm run lint && egg-bin test",
"ci": "egg-bin cov && npm run prepublishOnly && npm pack",
Expand Down Expand Up @@ -65,5 +63,7 @@
}
},
"type": "module",
"types": "./dist/commonjs/index.d.ts"
"types": "./dist/commonjs/index.d.ts",
"main": "./dist/commonjs/index.js",
"module": "./dist/esm/index.js"
}
29 changes: 24 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { EventEmitter } from 'node:events';

export type CallbackFunction = (err?: Error) => void;
export type ReadyFunctionArg = boolean | Error | CallbackFunction | undefined;
export type ReadyFunctionArg = boolean | Error | CallbackFunction;

export class Ready {
#isReady: boolean;
Expand All @@ -11,6 +13,8 @@ export class Ready {
this.#readyCallbacks = [];
}

ready(): Promise<void>;
ready(flagOrFunction: ReadyFunctionArg): void;
ready(flagOrFunction?: ReadyFunctionArg) {
// register a callback
if (flagOrFunction === undefined || typeof flagOrFunction === 'function') {
Expand All @@ -25,7 +29,7 @@ export class Ready {
* It will return promise when no argument passing.
*/
#register(func?: CallbackFunction) {
// support `this.ready().then(onready);` and `await this.ready()`;
// support `this.ready().then(onReady);` and `await this.ready()`;
if (!func) {
return new Promise<void>((resolve, reject) => {
function func(err?: Error) {
Expand All @@ -51,8 +55,8 @@ export class Ready {
}

/**
* Call the callbacks that has been registerd, and clean the callback stack.
* If the flag is not false, it will be marked as ready. Then the callbacks will be called immediatly when register.
* Call the callbacks that has been registered, and clean the callback stack.
* If the flag is not false, it will be marked as ready. Then the callbacks will be called immediately when register.
* @param {Boolean|Error} flag - Set a flag whether it had been ready. If the flag is an error, it's also ready, but the callback will be called with argument `error`
*/
#emit(flag: boolean | Error) {
Expand All @@ -76,8 +80,23 @@ export class Ready {
if (!obj) return;
const ready = new Ready();
// delegate method
obj.ready = (flagOrFunction: any) => ready.ready(flagOrFunction);
obj.ready = (flagOrFunction: any) => {
return ready.ready(flagOrFunction);
};
}
}

export default Ready;

export class ReadyEventEmitter extends EventEmitter {
#readyObj = new Ready();

ready(): Promise<void>;
ready(flagOrFunction: ReadyFunctionArg): void;
ready(flagOrFunction?: ReadyFunctionArg) {
if (flagOrFunction === undefined) {
return this.#readyObj.ready();
}
this.#readyObj.ready(flagOrFunction);
}
}
49 changes: 42 additions & 7 deletions test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { strict as assert } from 'node:assert';
import Ready, { ReadyFunctionArg, Ready as ReadyBase } from '../src/index.js';
import Ready, { ReadyFunctionArg, Ready as ReadyBase, ReadyEventEmitter } from '../src/index.js';

class SomeClass {
property: string;
Expand All @@ -10,8 +10,13 @@ class SomeClass {
this.#readyObject = new Ready();
}

ready(): Promise<void>;
ready(arg: ReadyFunctionArg): void;
ready(arg?: ReadyFunctionArg) {
return this.#readyObject.ready(arg);
if (arg === undefined) {
return this.#readyObject.ready();
}
this.#readyObject.ready(arg);
}

method() {
Expand All @@ -32,6 +37,22 @@ class ReadySubClass extends ReadyBase {
}
}

class ReadyEventClass extends ReadyEventEmitter {
property: string;

constructor() {
super();
this.property = 'value';
this.ready(() => {
this.emit('ready-event');
});
}

method() {
return 'method';
}
}

describe('Ready.mixin', () => {
it('should exports mixin', () => {
assert(Ready.mixin);
Expand Down Expand Up @@ -88,7 +109,7 @@ describe('new Ready()', () => {
assert.deepEqual(arr, [ 1, 2 ]);
});

it('should immediatly call callback when already ready', done => {
it('should immediately call callback when already ready', done => {
const someClass = new SomeClass();
someClass.ready(true);
someClass.ready(done);
Expand All @@ -113,11 +134,25 @@ describe('new Ready()', () => {
});
});

describe('new ReadyEventClass()', () => {
it('should have Ready properties', async () => {
const someClass = new ReadyEventClass();
assert('ready' in someClass);
let gotReadyEvent = false;
someClass.on('ready-event', () => {
gotReadyEvent = true;
});
someClass.ready(true);
await someClass.ready();
assert.equal(gotReadyEvent, true);
});
});

describe('promise', () => {
it('should resolve after ready', done => {
const someClass = new SomeClass();
someClass.ready()!.then(() => {
someClass.ready()!.then(done);
someClass.ready().then(() => {
someClass.ready().then(done);
});
someClass.ready(true);
});
Expand All @@ -144,7 +179,7 @@ describe('error', () => {

it('should get error in promise', done => {
const someClass = new SomeClass();
someClass.ready()!.catch(err => {
someClass.ready().catch(err => {
assert(err);
assert(err.message === 'error');
done();
Expand All @@ -165,7 +200,7 @@ describe('error', () => {
it('should get error after ready in promise', done => {
const someClass = new SomeClass();
someClass.ready(new Error('error'));
someClass.ready()!.catch(err => {
someClass.ready().catch(err => {
assert(err);
assert(err.message === 'error');
done();
Expand Down

0 comments on commit bb049ea

Please sign in to comment.