Skip to content

Commit

Permalink
feat(events): add off function return with on.
Browse files Browse the repository at this point in the history
  • Loading branch information
chizukicn committed Jul 11, 2023
1 parent 254c976 commit 8f9cc3d
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 64 deletions.
1 change: 0 additions & 1 deletion .prettierrc

This file was deleted.

2 changes: 1 addition & 1 deletion bench/cls.bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { bench, describe } from "vitest";
import classnames from "classnames";
import clsx from "clsx";
import classcat from "classcat";
import { cls } from "../dist/";
import { cls } from "../dist/index.mjs";
import pkg from "../package.json";
function getVersion(dep: string) {
const version = pkg.dependencies[dep] || pkg.devDependencies[dep];
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,18 @@
},
"devDependencies": {
"@curev/eslint-config": "^0.0.11",
"@vitest/coverage-v8": "^0.32.2",
"@vitest/coverage-v8": "^0.32.0",
"bumpp": "^9.1.1",
"changelogen": "^0.5.3",
"classcat": "^5.0.4",
"classnames": "^2.3.2",
"clsx": "^1.2.1",
"eslint": "^8.43.0",
"lint-staged": "^13.2.2",
"prettier": "^2.8.8",
"simple-git-hooks": "^2.8.1",
"typescript": "^5.1.3",
"unbuild": "^1.2.1",
"vitest": "^0.32.2"
"vitest": "^0.32.0"
},
"packageManager": "[email protected]",
"simple-git-hooks": {
Expand Down
19 changes: 5 additions & 14 deletions pnpm-lock.yaml

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

29 changes: 18 additions & 11 deletions src/each.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { range } from "./range";
import { isArray, isIterable, isNumber, isObject } from "./shared";
import { isIterable, isNumber, isObject } from "./shared";

export function renderList<U>(source: string, render: (item: string, index: number) => U): U[];

Expand All @@ -12,20 +11,28 @@ export function renderList<U>(source: number, render: (item: number, index: numb
export function renderList<T, U>(source: T, render: <K extends keyof T>(item: T[K], key: T[K], index: number) => U): U[];

export function renderList(source: any, render: (...args: any[]) => any) {
if (isArray(source)) {
return source.map(render);
const result: any[] = [];

if (isIterable(source)) {
let index = 0;
for (const item of source) {
result.push(render(item, index++));
}
} else if (isNumber(source)) {
return range(1, source + 1).map(render);
} else if (isIterable(source)) {
return Array.from(source).map(render);
}
if (isObject(source)) {
return Object.keys(source).map((key, index) => render(source[key], key, index));
for (let i = 0; i < source; i++) {
result.push(render(i + 1, i));
}
} else if (isObject(source)) {
let index = 0;
for (const key in source) {
result.push(render(source[key], key, index++));
}
}
return [];
return result;
}

/**
* @alias renderList
*/
export const each = renderList;

70 changes: 38 additions & 32 deletions src/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,31 @@ export type EventType = string | symbol;
// An event handler can take an optional event argument
// and should not return a value
export type Handler<T extends unknown[]> = (...event: T) => void;
export type WildcardHandler<T extends Record<EventType, unknown[]>> = (
type: keyof T,
...event: T[keyof T]
) => void;

// An array of all currently registered event handlers for a type
export type EventHandlerList<T extends unknown[]> = Array<Handler<T>>;
export type WildCardEventHandlerList<T extends Record<EventType, unknown[]>> = Array<
WildcardHandler<T>
>;

// A map of event types and their corresponding event handlers.
export type EventHandlerMap<Events extends Record<EventType, unknown[]>> = Map<
keyof Events | "*",
EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
keyof Events,
EventHandlerList<Events[keyof Events]>
>;

export type ListenObject<Events extends Record<EventType, unknown[]>> = Record <keyof Events, Handler<Events[keyof Events]>>;

export interface Emitter<Events extends Record<EventType, unknown[]>> {
all: EventHandlerMap<Events>

on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): this
on(type: "*", handler: WildcardHandler<Events>): this
on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): () => void

once<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): () => void

listen<O extends ListenObject<Events>>(map: O): Record<keyof O, () => void>

off<Key extends keyof Events>(
type: Key,
handler?: Handler<Events[Key]>
): this
off(type: "*", handler: WildcardHandler<Events>): this
off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): this

emit<Key extends keyof Events>(type: Key, ...event: Events[Key]): this

}

/**
Expand All @@ -45,9 +40,6 @@ export interface Emitter<Events extends Record<EventType, unknown[]>> {
export function mitt<Events extends Record<EventType, unknown[]>>(
source?: EventHandlerMap<Events>
): Emitter<Events> {
type GenericEventHandler =
| Handler<Events[keyof Events]>
| WildcardHandler<Events>;
const all = source ?? new Map<EventType, EventHandlerList<Events[keyof Events]>>();

return {
Expand All @@ -62,14 +54,32 @@ export function mitt<Events extends Record<EventType, unknown[]>>(
* @param {Function} handler Function to call in response to given event
* @memberOf mitt
*/
on<Key extends keyof Events>(this: Emitter<Events>, type: Key, handler: GenericEventHandler) {
const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
on<Key extends keyof Events>(this: Emitter<Events>, type: Key, handler: Handler<Events[Key]>) {
const handlers: Array<Handler<Events[Key]>> | undefined = all.get(type);
if (handlers) {
handlers.push(handler);
} else {
all.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
}
return this;
return () => {
this.off(type, handler);
};
},

listen<O extends ListenObject<Events>>(this: Emitter<Events>, map: O) {
const off = {} as Record<keyof O, () => void>;
for (const [type, handler] of Object.entries(map)) {
this.on(type as keyof Events, handler);
}
return off;
},

once<Key extends keyof Events>(this: Emitter<Events>, type: Key, handler: Handler<Events[Key]>) {
const off = this.on(type, (...args) => {
off();
handler(...args);
});
return off;
},

/**
Expand All @@ -79,11 +89,14 @@ export function mitt<Events extends Record<EventType, unknown[]>>(
* @param {Function} [handler] Handler function to remove
* @memberOf mitt
*/
off<Key extends keyof Events>(this: Emitter<Events>, type: Key, handler?: GenericEventHandler) {
const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
off<Key extends keyof Events>(this: Emitter<Events>, type: Key, handler?: Handler<Events[Key]>) {
const handlers: Array<Handler<Events[Key]>> | undefined = all!.get(type);
if (handlers) {
if (handler) {
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
if (handlers.length === 0) {
all.delete(type);
}
} else {
all.delete(type);
}
Expand All @@ -102,21 +115,14 @@ export function mitt<Events extends Record<EventType, unknown[]>>(
* @memberOf mitt
*/
emit<Key extends keyof Events>(this: Emitter<Events>, type: Key, ...evt: Events[Key]) {
let handlers = all.get(type);
const handlers = all.get(type);
if (handlers) {
(handlers as EventHandlerList<Events[keyof Events]>).forEach(
(handler) => {
handler(...evt);
}
);
}

handlers = all.get("*");
if (handlers) {
(handlers as WildCardEventHandlerList<Events>).forEach((handler) => {
handler(type, ...evt);
});
}
return this;
}
};
Expand Down
4 changes: 2 additions & 2 deletions test/event.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { mitt } from "../src/event";

test("emitter", () => {
const emitter = mitt();
emitter.on("foo", () => {
const off = emitter.on("foo", () => {
expect(true).toBe(true);
});

emitter.emit("foo");

emitter.off("foo");
off();

expect(emitter.all.size).toBe(0);
});

0 comments on commit 8f9cc3d

Please sign in to comment.