Skip to content

Commit

Permalink
feat: export isReady and readyError getter (#6)
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 a new development dependency for improved tooling.
- Introduced new getter methods for better access to readiness state and
errors.

- **Bug Fixes**
- Enhanced error handling and clarity in the `Ready` class
functionality.
- Updated tests to ensure correct behavior of the `ready` method under
various conditions.

- **Chores**
- Updated `.gitignore` to exclude `package-lock.json` from version
control.
	- Modified CI script for packaging during continuous integration.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
fengmk2 authored Dec 18, 2024
1 parent e771131 commit cce2f08
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 20 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ jobs:
name: Node.js
uses: node-modules/github-actions/.github/workflows/node-test.yml@master
with:
version: '16.17.0, 16, 18, 20, 22'
os: 'ubuntu-latest'
version: '16.17.0, 16, 18, 20, 22, 23'
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
23 changes: 23 additions & 0 deletions .github/workflows/pkg.pr.new.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Publish Any Commit
on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: 20

- name: Install dependencies
run: npm install

- name: Build
run: npm run prepublishOnly --if-present

- run: npx pkg-pr-new publish
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ lib
bun.lockb
.tshy*
dist
package-lock.json
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
],
"dependencies": {},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.1",
"@eggjs/tsconfig": "^1.3.3",
"@types/mocha": "^10.0.2",
"@types/node": "^20.8.4",
Expand All @@ -24,7 +25,7 @@
"scripts": {
"lint": "eslint src test --ext ts",
"test": "npm run lint && egg-bin test",
"ci": "egg-bin cov && npm run prepublishOnly && npm pack",
"ci": "egg-bin cov && npm run prepublishOnly && attw --pack",
"clean": "tsc -b --clean",
"prepublishOnly": "tshy && tshy-after"
},
Expand Down
44 changes: 30 additions & 14 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { EventEmitter } from 'node:events';

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

export class Ready {
#isReady: boolean;
#readyCallbacks: CallbackFunction[];
#readyArg?: Error = undefined;
#readyError?: Error;

constructor() {
this.#isReady = false;
Expand All @@ -20,16 +20,24 @@ export class Ready {
if (flagOrFunction === undefined || typeof flagOrFunction === 'function') {
return this.#register(flagOrFunction);
}
// emit callbacks
// get ready and emit callbacks
this.#emit(flagOrFunction);
}

get isReady(): boolean {
return this.#isReady;
}

get readyError() {
return this.#readyError;
}

/**
* Register a callback to the callback stack, it will be called when emit.
* 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 @@ -40,15 +48,15 @@ export class Ready {
}
}
if (this.#isReady) {
return func(this.#readyArg);
return func(this.#readyError);
}
this.#readyCallbacks.push(func);
});
}

// this.ready(fn)
if (this.#isReady) {
func(this.#readyArg);
func(this.#readyError);
} else {
this.#readyCallbacks.push(func);
}
Expand All @@ -60,16 +68,16 @@ export class Ready {
* @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) {
// this.ready(true);
// this.ready(false);
// this.ready(err);
this.#isReady = flag !== false;
this.#readyArg = flag instanceof Error ? flag : undefined;
// this.ready(true)
// this.ready(err)
// this.ready(false)
this.#isReady = flag !== false;
this.#readyError = flag instanceof Error ? flag : undefined;
// this.ready(true) or this.ready(err)
if (this.#isReady) {
this.#readyCallbacks
.splice(0, Infinity)
.forEach(callback => process.nextTick(() => callback(this.#readyArg)));
.forEach(callback => process.nextTick(() => callback(this.#readyError)));
}
}

Expand All @@ -78,10 +86,10 @@ export class Ready {
*/
static mixin(obj?: any) {
if (!obj) return;
const ready = new Ready();
const readyObject = new Ready();
// delegate method
obj.ready = (flagOrFunction: any) => {
return ready.ready(flagOrFunction);
return readyObject.ready(flagOrFunction);
};
}
}
Expand All @@ -99,4 +107,12 @@ export class ReadyEventEmitter extends EventEmitter {
}
this.#readyObj.ready(flagOrFunction);
}

get isReady(): boolean {
return this.#readyObj.isReady;
}

get readyError() {
return this.#readyObj.readyError;
}
}
58 changes: 55 additions & 3 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ class ReadyEventClass extends ReadyEventEmitter {
}

describe('Ready.mixin', () => {
it('should exports mixin', () => {
it('should exports mixin', async () => {
assert(Ready.mixin);
const someObject: any = {};
Ready.mixin(someObject);
someObject.ready(true);
await someObject.ready();
});

it('should exports Ready', () => {
Expand Down Expand Up @@ -145,6 +149,17 @@ describe('new ReadyEventClass()', () => {
someClass.ready(true);
await someClass.ready();
assert.equal(gotReadyEvent, true);

assert.equal(someClass.isReady, true);
assert.equal(someClass.readyError, undefined);

// ready with error
someClass.ready(new Error('mock error'));
await assert.rejects(async () => {
await someClass.ready();
}, /mock error/);
assert.equal(someClass.isReady, true);
assert.equal(someClass.readyError!.message, 'mock error');
});
});

Expand Down Expand Up @@ -181,7 +196,7 @@ describe('error', () => {
const someClass = new SomeClass();
someClass.ready().catch(err => {
assert(err);
assert(err.message === 'error');
assert.equal(err.message, 'error');
done();
});
someClass.ready(new Error('error'));
Expand All @@ -192,7 +207,7 @@ describe('error', () => {
someClass.ready(new Error('error'));
someClass.ready(err => {
assert(err);
assert(err.message === 'error');
assert.equal(err.message, 'error');
done();
});
});
Expand All @@ -206,6 +221,43 @@ describe('error', () => {
done();
});
});

it('should await ready error', async () => {
const someClass = new ReadySubClass();
someClass.ready(new Error('mock async before error'));
await assert.rejects(async () => {
await someClass.ready();
}, /mock async before error/);

// again should throw error too
await assert.rejects(async () => {
await someClass.ready();
}, /mock async before error/);
assert(someClass.readyError instanceof Error);
assert.equal(someClass.isReady, true);

// set to false then ready again
someClass.ready(false);
assert.equal(someClass.isReady, false);
assert.equal(someClass.readyError, undefined);

setTimeout(() => {
someClass.ready(true);
}, 10);
await someClass.ready();
assert.equal(someClass.readyError, undefined);
assert.equal(someClass.isReady, true);
});

it('should await ready error', async () => {
const someClass = new SomeClass();
setTimeout(() => {
someClass.ready(new Error('mock async after error'));
}, 10);
await assert.rejects(async () => {
await someClass.ready();
}, /mock async after error/);
});
});

describe('work on Ready SubClass', () => {
Expand Down

0 comments on commit cce2f08

Please sign in to comment.