@travetto/registry
Version:
Patterns and utilities for handling registration of metadata and functionality for run-time use
60 lines (49 loc) • 1.75 kB
text/typescript
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;
}
}