diff --git a/.eslintignore b/.eslintignore index 0a00463..399f374 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,2 @@ dist -__test__ -node_modules -website \ No newline at end of file +node_modules \ No newline at end of file diff --git a/__test__/hello.test.js b/__test__/hello.test.js deleted file mode 100644 index 467ca8d..0000000 --- a/__test__/hello.test.js +++ /dev/null @@ -1,6 +0,0 @@ -import { test, expect } from "vitest"; -import { sayHello } from "../src"; - -test("hello world", () => { - expect(sayHello()).toBe("Hello World"); -}); diff --git a/__test__/hello.test.ts b/__test__/hello.test.ts new file mode 100644 index 0000000..20a1f50 --- /dev/null +++ b/__test__/hello.test.ts @@ -0,0 +1,41 @@ +import { describe } from "vitest"; +import { test, expect } from "vitest"; +import miis from "../src"; + +describe("basic useage", () => { + test("subscribe", async () => { + await new Promise((resolve) => { + miis.subscribe("a", resolve); + miis.dispatch("a"); + }); + }); + + test("unsubscribe", async () => { + await new Promise((resolve, reject) => { + const unsubscribe = miis.subscribe("b", reject); + unsubscribe(); + miis.dispatch("b"); + setTimeout(resolve, 10); + }); + }); +}); + +describe("arguments", () => { + test("single", async () => { + const result = await new Promise((resolve) => { + miis.subscribe("b", resolve); + miis.dispatch("b", 1); + }); + expect(result).toBe(1); + }); + + test("multi", async () => { + const result = await new Promise((resolve) => { + miis.subscribe("b", (...args) => { + resolve(Array.from(args)); + }); + miis.dispatch("b", 2, 3, 4); + }); + expect(result).toEqual([2, 3, 4]); + }); +}); diff --git a/package.json b/package.json index c2eb43b..f70c36c 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,23 @@ { "name": "miis", "version": "0.0.1", - "description": "Simple Start Template", + "description": "Tiny functional event subscriber and dispatcher.", "main": "index.ts", "scripts": { "build": "rollup -c rollup.config.js", "lint": "npx eslint src/**", - "prettier": "npx prettier src/** --write", + "prettier": "npx prettier src/** --write && npx prettier __test__/** --write", "test": "npx vitest", "test:run": "npx vitest run", "test:coverrage": "npx vitest --coverage", "publish": "npm run build && npm publish" }, "keywords": [ - "vite", - "vitest", - "docusaurus", - "template" + "event", + "emitter", + "subscribe", + "dispatch", + "linstener" ], "author": "Yukiniro", "license": "MIT", @@ -44,5 +45,8 @@ "tslib": "^2.3.1", "typescript": "^4.6.4", "vitest": "^0.12.2" + }, + "dependencies": { + "bittydash": "^0.1.1" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0702bbc..3b05b65 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,7 @@ specifiers: '@rollup/plugin-node-resolve': ^13.3.0 '@rollup/plugin-typescript': ^8.3.1 '@yukiniro/eslint-config': ^0.0.3 + bittydash: ^0.1.1 eslint: ^8.11.0 prettier: ^2.6.0 prettier-eslint: ^13.0.0 @@ -21,6 +22,9 @@ specifiers: typescript: ^4.6.4 vitest: ^0.12.2 +dependencies: + bittydash: 0.1.1 + devDependencies: '@babel/core': 7.17.8 '@babel/plugin-transform-modules-commonjs': 7.17.7_@babel+core@7.17.8 @@ -1832,6 +1836,10 @@ packages: tweetnacl: 0.14.5 dev: true + /bittydash/0.1.1: + resolution: {integrity: sha512-ZfMy9OJB0Aeo183YclzIhxvCeA3D9aVj5gE3STBg+sOsBzKkZmjXvIbvq8FHNvDRjcF7CcwF9yRnu5ylVd9MyQ==} + dev: false + /boxen/5.1.2: resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} engines: {node: '>=10'} diff --git a/src/index.ts b/src/index.ts index ed8e3e9..7ff8280 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,48 @@ -export const sayHello = function () { - return "Hello World"; -} \ No newline at end of file +import { remove } from "bittydash"; + +type Listener = (...args: any[]) => void; +type EventName = string | symbol; +type Options = { + once: boolean; +}; +type Subscriber = { + listener: Listener; + once: boolean; +}; + +const handlerMap = new Map(); + +function subscribe( + key: EventName, + listener: Listener, + options?: Options +): () => void { + if (!handlerMap.has(key)) { + handlerMap.set(key, []); + } + const list = handlerMap.get(key); + const { once } = options || {}; + const item = { listener, once }; + list.push(item); + return () => { + remove(list, item); + }; +} + +function dispatch(key: EventName, ...args: any[]) { + const list = handlerMap.get(key) || []; + const removeList = []; + list.forEach((item: Subscriber) => { + const { listener, once } = item; + listener(...args); + if (once) { + removeList.push(item); + } + }); + removeList.forEach((item: Subscriber) => remove(list, item)); +} + +export default { + subscribe, + dispatch, +};