Gathering detailed insights and metrics for fsa-emitter
Gathering detailed insights and metrics for fsa-emitter
Gathering detailed insights and metrics for fsa-emitter
Gathering detailed insights and metrics for fsa-emitter
npm install fsa-emitter
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
1 Stars
147 Commits
3 Watching
18 Branches
2 Contributors
Updated on 14 Dec 2022
TypeScript (90.57%)
JavaScript (8.15%)
Shell (1.28%)
Cumulative downloads
Total Downloads
Last day
2,700%
28
Compared to previous day
Last week
5,175%
211
Compared to previous week
Last month
2,780%
288
Compared to previous month
Last year
-17.8%
698
Compared to previous year
32
EventEmitter
in FSA style.
When dealing with event, I find myself need to remember the name of the event, and the parameters each event has.
The person who defines the events and the person who consumes the events can be two different people.
This implicit knowledge coupling relies on communication and documentation that are prone to error, and are not convenient.
This library addresses this issue by emitting and consuming events using a standard format, and provides IDE type support, so they can be consumed easily.
@unional/events-plus is the spiritual successor of this package. It works with multiple event emitters with similar API. Feel free to check it out.
One of the benefits of using events is decoupling. Here is one way to organize your code:
1// app.ts 2import { doWork } from './doWork' 3 4const emitter = new Emitter() 5 6doWork({ emitter }) 7 8// doWork.ts 9import { createEvent, Emitter } from 'fsa-emitter' 10 11export const count = createEvent<number>('count') 12 13export function doWork({ emitter }) { 14 emitter.emit(count(1, undefined)) 15} 16 17// in UI 18import { count } from './doWork' 19 20emitter.on(count, payload => { 21 console.log('payload is typed and is a number: ', payload) 22})
1npm install fsa-emitter
Emitter
uses FluxStandardAction
as the standard event format.
Another key difference between Emitter
and NodeJS EventEmitter
is that Emitter
will capture any error thrown in listener and send it to console.error()
.
This avoids any listener code throws error and break the event emitting logic.
To create event, use one of the helper methods below:
1import { 2 createEvent, 3 createScopedCreateEvent, 4 createEventAction, 5 createScopedCreateEventAction, 6 Emitter 7} from 'fsa-emitter' 8 9const count = createEvent<number>('count') 10 11// create scoped event 12const createMyModuleEvent = createScopedCreateEvent('myModule') 13// `scopedCount` will emit FSA with `type: 'myModule/count'` 14const scopedCount = createMyModuleEvent<number>('count') 15 16const add = createAction< 17 /* input */ { a: number, b: number }, 18 /* payload */ number>('add', ({ a, b }) => emit => emit(a + b)) 19 20// create scoped action 21const createMyModuleAction = createScopedCreateEventAction('myModule') 22// `scopedCountAction` will emit FSA with `type: 'myModule/add'` 23const scopedAdd = createMyModuleAction< 24 /* input */ { a: number, b: number }, 25 /* payload */ number>('add', ({ a, b }) => emit => emit(a + b)) 26 27const emitter = new Emitter() 28 29emitter.emit(count(1, undefined)) 30emitter.emit(scopedCount(2, undefined)) 31add(emitter, { a: 1, b: 2 }, undefined) 32scopedAdd(emitter, { a: 1, b: 2 }, undefined)
Note that due to https://github.com/Microsoft/TypeScript/issues/12400,
you need to supply undefined
at where they expect meta
.
To consume the event, use one of the following methods:
1import { createEvent, Emitter } from 'fsa-emitter'
2
3const count = createEvent<number>('count')
4const emitter = new Emitter()
5
6emitter.addListener(count, value => console.info(value))
7emitter.on(count, value => console.info(value))
8
9// Will only listen to the event once
10emitter.once(count, value => console.info(value))
11
12// line up in queue to listen for the event once
13emitter.queue(count, value => console.info(value))
14
15// listen to all events
16emitter.onAny(fsa => console.info(fsa.type, fsa.payload))
17
18// listen to any event that does not have a listener
19emitter.onMissed(fsa => console.info(fsa.type, fsa.payload))
Command
is a simple command pattern that provides a simple way to manage dependencies.
1import { Command, createEvent, Emitter } from 'fsa-emitter' 2 3const count = createEvent<{ n: number }>('count') 4 5class CountCommand extends Command { 6 run(n: number) { 7 while (n) { 8 this.emitter.emit(count({ n }, undefined)) 9 n-- 10 } 11 } 12} 13 14const emitter = new Emitter() 15const cmd = new CountCommand({ emitter }) 16cmd(10)
1import { Command, createEvent, Emitter } from 'fsa-emitter' 2 3const changeHeight = createEvent<{ height: number }>('changeHeight') 4const landed = createEvent('landed') 5 6class FlyCommand extends Command<{ fuel: number }> { 7 fuel: number 8 height = 0 9 run() { 10 while (this.fuel > 0) { 11 this.height += 100 12 this.fuel-- 13 this.emitter.emit(changeHeight({ height: this.height }, undefined)) 14 } 15 const gliding = setInterval(() => { 16 this.height -= 50 17 this.emitter.emit(changeHeight({ height: this.height }, undefined)) 18 if (this.height <= 0) { 19 this.emitter.emit(landed(undefined, undefined)) 20 clearInterval(gliding) 21 } 22 }, 100) 23 } 24} 25 26// `fuel` is in the constructor context 27const fly = new FlyCommand({ emitter: new Emitter(), fuel: 10 }) 28fly.run()
TestEmitter
TestEmitter
can be used as a drop-in replacement as Emitter
during test.
The difference between TestEmitter
and Emitter
is that TestEmitter
will not capture errors thrown in listeners.
This make it more suitable to use during testing so that you can detect any error thrown during the test.
Also, it provides some additional methods:
listenerCalled(event: TypedEvent | string): boolean
1import { TestEmitter, createEvent } from 'fsa-emitter' 2 3const emitter = new TestEmitter() 4const count = createEvent<number>('count') 5emitter.on(count, () => ({})) 6t.false(emitter.listenerCalled(count)) 7 8emitter.emit(count(1, undefined)) 9t.true(emitter.listenerCalled(count)) 10t.true(emitter.listenerCalled(count.type))
allListenersCalled(): boolean
1import { TestEmitter, createEvent } from 'fsa-emitter' 2 3const emitter = new TestEmitter() 4const count = createEvent<number>('count') 5const bound = createEvent<number>('bound') 6 7emitter.on(count, () => ({})) 8emitter.on(bound, () => ({})) 9 10emitter.emit(count(1, undefined)) 11 12t.false(emitter.allListenersCalled()) 13 14emitter.emit(bound(1, undefined)) 15 16t.true(emitter.allListenersCalled())
listenedTo(events: (TypedEvent | string)[] | { [k]: TypedEvent })
1import { TestEmitter, createEvent } from 'fsa-emitter' 2 3const emitter = new TestEmitter() 4const count = createEvent<number>('count') 5const bound = createEvent<number>('bound') 6 7emitter.on(count, () => ({})) 8 9emitter.listenedTo([count]) // true 10emitter.listenedTo({ count }) // true 11emitter.listenedTo(['count']) // true 12 13emitter.listenedTo([ bound ]) // false 14emitter.listenedTo({ bound }) // false 15emitter.listenedTo([ 'bound' ]) // false
setupCommandTest(Command, context?)
setupCommandTest()
is a simple helper to create a TestEmitter
for the command to run with.
The same completion support is available as in the Command
constructor.
1import { Command, createEvent, setupCommandTest } from 'fsa-emitter' 2 3const count = createEvent<{ n: number }>('count') 4 5class CountCommand extends Command { 6 ... 7} 8 9const { command, emitter } = setupCommandTest(CountCommand) 10 11class FlyCommand extends Command<{ fuel: number }> { 12 ... 13} 14 15// completion is available for `fuel` 16const { command, emitter } = setupCommandTest(FlyCommand, { fuel: 10 })
1# after fork and clone 2npm install 3 4# begin making changes 5git checkout -b <branch> 6npm run watch 7 8# after making change(s) 9git commit -m "<commit message>" 10git push 11 12# create PR
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
no dangerous workflow patterns detected
Reason
license file detected
Details
Reason
security policy file detected
Details
Reason
SAST tool detected but not run on all commits
Details
Reason
9 existing vulnerabilities detected
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
project is not fuzzed
Details
Score
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More