Skip to content

Instantly share code, notes, and snippets.

@3AHAT0P
Last active June 10, 2021 11:43
Show Gist options
  • Save 3AHAT0P/9e0da3e36a9eefb51f9ba78b604c6629 to your computer and use it in GitHub Desktop.
Save 3AHAT0P/9e0da3e36a9eefb51f9ba78b604c6629 to your computer and use it in GitHub Desktop.
My implementation matcher pattern (switch/case or some sequence if/else analogue)
import { Matcher, MatcherFn, Listener } from './Matcher';
type EventName = 'A' | 'B' | 'AB' | 'BA' | 'BC' | 'CB' | 'CCAAAC';
type ExtendedEventName = EventName | 'A or C without B' | 'C';
const main = async () => {
const matcher = new Matcher<EventName, ExtendedEventName, { someField: number }>();
matcher
.addMatcher((event) => (event !== 'A' && event.includes('A')) ? 'A' : null)
.addMatcher((event) => event.includes('C') ? 'C' : null)
.addMatcher((event) => {
if (event.includes('A') && !event.includes('B')) return 'A or C without B';
if (event.includes('C') && !event.includes('B')) return 'A or C without B';
return null;
})
;
matcher
.on('A', ({ someField }) => { console.log('A happened', someField); })
.on('B', ({ someField }) => { console.log('B happened', someField); })
.on('C', ({ someField }) => { console.log('C happened', someField); })
.on('A or C without B', ({ someField }) => { console.log('A or C without B happened', someField); });
await matcher.run('A', { someField: 1 });
await matcher.run('BA', { someField: 2 });
await matcher.run('B', { someField: 3 });
await matcher.run('BC', { someField: 4 });
await matcher.run('AB', { someField: 5 });
await matcher.run('CCAAAC', { someField: 6 });
}
main();
export type Listener<TContext> = (context: TContext) => Promise<void> | void;
export type MatcherFn<TEvent extends string> = (event: TEvent) => TEvent | null;
export class Matcher<
TEvent extends string, TAdditionalEvent extends string = 'DEFAULT', TContext = any,
> {
private _listeners: Map<TEvent | TAdditionalEvent, Listener<TContext>[]> = new Map();
private _customMatchers: MatcherFn<TEvent | TAdditionalEvent>[] = [];
private async _trigger(subtype: TEvent | TAdditionalEvent, context: TContext): Promise<void> {
const listeners = this._listeners.get(subtype);
if (listeners != null && listeners.length > 0) {
for (const listener of listeners) await listener(context);
}
}
public addMatcher(cb: MatcherFn<TEvent | TAdditionalEvent>): this {
this._customMatchers.push(cb);
return this;
}
public on(event: TEvent | TAdditionalEvent, cb: Listener<TContext>): this {
const listeners = this._listeners.get(event);
if (listeners == null) this._listeners.set(event, [cb]);
else listeners.push(cb);
return this;
}
public async run(event: TEvent, context: TContext): Promise<void> {
for (const matcher of this._customMatchers) {
const _event = matcher(event);
if (_event !== null) await this._trigger(_event, context);
}
await this._trigger(event, context);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment