UNPKG

@travetto/registry

Version:

Patterns and utilities for handling registration of metadata and functionality for run-time use

60 lines (49 loc) 1.75 kB
import { EventEmitter } from 'node:events'; import { Class, describeFunction } from '@travetto/runtime'; import { ChangeSource, ChangeEvent, ChangeHandler } from '../types'; /** * Change source specific to individual methods of classes. Useful * for method based registries */ export class MethodSource implements ChangeSource<[Class, Function]> { #emitter = new EventEmitter(); /** * Define parent change source, generally will be the class source */ constructor(classSource: ChangeSource<Class>) { classSource.on(e => this.onClassEvent(e)); } async init(): Promise<void> { } emit(ev: ChangeEvent<[Class, Function]>): void { this.#emitter.emit('change', ev); } /** * On a class being emitted, check methods */ onClassEvent(e: ChangeEvent<Class>): void { const next = describeFunction(e.curr!)?.methods ?? {}; const prev = describeFunction(e.prev!)?.methods ?? {}; /** * Go through each method, comparing hashes. To see added/removed and changed */ for (const k of Object.keys(next)) { if (!prev[k] || !e.prev) { this.emit({ type: 'added', curr: [e.curr!, e.curr!.prototype[k]] }); } else if (next[k].hash !== prev[k].hash && e.curr) { // FIXME: Why is e.prev undefined sometimes? this.emit({ type: 'changed', curr: [e.curr, e.curr.prototype[k]], prev: [e.prev, e.prev.prototype[k]] }); } else { // Method Unchanged } } for (const k of Object.keys(prev)) { if (!next[k] && e.prev) { this.emit({ type: 'removing', prev: [e.prev, e.prev.prototype[k]] }); } } } on(callback: ChangeHandler<[Class, Function]>): this { this.#emitter.on('change', callback); return this; } }