Skip to content

Commit

Permalink
feat: wildcard support
Browse files Browse the repository at this point in the history
Closes #3
  • Loading branch information
Can Küçükyılmaz committed Mar 1, 2022
1 parent 264d980 commit 3469816
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/integration.yaml
Expand Up @@ -2,7 +2,7 @@ name: Integration

on:
push:
branches: [main, develop]
branches: [develop]
pull_request:
branches: [main, develop]
jobs:
Expand Down
40 changes: 40 additions & 0 deletions README.md
Expand Up @@ -56,6 +56,46 @@ import pubsub from 'tiny-tiny-pubsub';
pubsub.clear();
```

### Wildcard support

Pubsub be able to support **wildcard** text matching.

For example:

If there are event registrations as below and user calls it with `trigger` method.

```javascript
pubsub.on("john", () => console.log("john");
pubsub.on("john.doe", () => console.log("john's name");
pubsub.on("john.doe.mail", () => console.log("john's mail");
pubsub.trigger("john.*")
```
all previously defined functions must be called except "john".
```javascript
// console output
"john's name";
"john's mail";
```
or user should be able to remove event listeners based on wildcards.
```javascript
pubsub.off('john.*');
pubsub.trigger('john');
pubsub.trigger('john.doe');
pubsub.trigger('john.doe.mail');
```
```javascript
// console output
'john';
```
there must be only one listener in listeners array that is "john"
Because user removed all listeners which matched with wildcard query that ends with asterix except "john".
### Licence
MIT
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -6,8 +6,8 @@
"types": "lib/pubsub.d.ts",
"scripts": {
"test": "jest --config jestconfig.json",
"test:ci": "npm run test --ci",
"test:watch": "npm run test --watch",
"test:ci": "npm run test -- --ci",
"test:watch": "npm run test -- --watch",
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
"lint": "tslint -p tsconfig.json",
"build": "tsc",
Expand Down
61 changes: 57 additions & 4 deletions src/pubsub.ts
Expand Up @@ -12,6 +12,31 @@ interface PubSubInterface {
class PubSub implements PubSubInterface {
private listeners: { [key: string]: Fn[] } = {};

/**
*
* @param name - event name
* @param callback - callback will fired if its matches
* @returns {boolean}
*/
private hasWildcard(name: string, callback: (key: string) => void): boolean {
const index = name.indexOf('*');

if (index > -1) {
const nameWithoutAsterix = name.slice(0, index);
const keys = Object.keys(this.listeners);

for (const key of keys) {
if (key.startsWith(nameWithoutAsterix)) {
callback(key);
}
}

return true;
}

return false;
}

/**
* it registers a new event with provided values
*
Expand All @@ -33,10 +58,21 @@ class PubSub implements PubSubInterface {
* @example
* pubsub.off('test', predefinedFn);
*
* @example
* // with wildcard
* pubsub.off('test.*');
*
* @param name {string} - event name
* @param fn {function} callback function
* @returns {void}
*/
off(name: string, fn: Fn) {
off(name: string, fn?: Fn) {
const completed = this.hasWildcard(name, (key) => delete this.listeners[key]);

if (completed) {
return true;
}

if (this.listeners[name]) {
for (let i = 0; i < this.listeners[name].length; i++) {
if (this.listeners[name][i] === fn) {
Expand All @@ -53,26 +89,43 @@ class PubSub implements PubSubInterface {
* @example
* * // without any data
* pubsub.trigger("test");
* @example
* // with string type data
* pubsub.trigger("test", "nothing");
* @example
* // with object type data
* pubsub.trigger("test", {'hello', 'world'});
*
* @example
* // with wildcard
* pubsub.trigger("test.*", "data");
*
* @param name event name
* @param data callback data
* @returns {void}
*/
trigger(name: string, data?: any) {
if (this.listeners[name]) {
this.listeners[name].forEach((fn: (data: any) => void) => {
const triggerAll = (key: string) => {
this.listeners[key].forEach((fn: (data: any) => void) => {
fn(data);
});
};
const completed = this.hasWildcard(name, (key) => {
triggerAll(key);
});

if (completed) {
return true;
}

if (this.listeners[name]) {
triggerAll(name);
}
}

/**
* clears all listener
* returns {void}
* @returns {void}
*/
clear() {
this.listeners = {};
Expand Down
27 changes: 26 additions & 1 deletion test/pubsub.test.ts
Expand Up @@ -21,6 +21,17 @@ describe('pubSub', () => {
expect(pubSub._listeners()).toEqual({ test: [] });
});

test('event remove successfully with wildcard', () => {
const fn = jest.fn();

pubSub.on('test', fn);
pubSub.on('test.driven', fn);
pubSub.on('test.driven.development', fn);

pubSub.off('test.*');
expect(pubSub._listeners()).toEqual({ test: [fn] });
});

test('event should be triggered', () => {
const fn = jest.fn();

Expand All @@ -29,6 +40,21 @@ describe('pubSub', () => {
expect(fn).toHaveBeenCalled();
});

test('event should be triggered with wildcard', () => {
const fn = jest.fn();
const fn2 = jest.fn();
const fn3 = jest.fn();

pubSub.on('test', fn);
pubSub.on('test.driven', fn2);
pubSub.on('test.driven.development', fn3);

pubSub.trigger('test*');
expect(fn).toHaveBeenCalled();
expect(fn2).toHaveBeenCalled();
expect(fn3).toHaveBeenCalled();
});

test('event should be triggered with data', () => {
const fn = jest.fn();

Expand All @@ -39,7 +65,6 @@ describe('pubSub', () => {

test('clear all listeners', () => {
const fn = jest.fn();
const fn2 = jest.fn();

pubSub.on('test', fn);
pubSub.clear();
Expand Down

0 comments on commit 3469816

Please sign in to comment.