UNPKG

@thisisagile/easy

Version:

Straightforward library for building domain-driven microservice architectures

65 lines (49 loc) 2.23 kB
import 'reflect-metadata'; import { List, toList } from './List'; import { isDefined } from './Is'; import { on, use } from './Constructor'; import { Optional } from './Types'; import { Entry, entries, values } from './Object'; type MetaParseOptions = { initial?: any; skipUndefined?: boolean }; class ClassMeta { constructor( readonly subject: any, private readonly data: any = (subject.prototype ?? subject).constructor ) {} get = <T>(key: string): T => Reflect.getMetadata(key, this.data) as T; set = <T>(key: string, value: T): T => { Reflect.defineMetadata(key, value, this.data); return value; }; entries = <T = unknown>(): List<Entry<T>> => entries<T>(this.subject); parse = <Out, Value>(f: (v: Value) => Out, options: MetaParseOptions = {}): Record<string, Out> => { const { initial = {}, skipUndefined = false } = options; return this.entries<Value>().reduce((a, [k, val]) => use(f(val), v => (isDefined(v) || !skipUndefined ? on(a, a => (a[k] = v)) : a)), initial); }; properties = (key?: string): List<PropertyMeta> => toList([...Object.getOwnPropertyNames(this.subject), ...Object.getOwnPropertyNames(Object.getPrototypeOf(this.subject))]) .map(p => this.property(p)) .filter(p => (key ? p.get(key) : p)); keys = <T = any>(key: string): List<T> => this.properties() .map(p => p.get<T>(key)) .reduce((list, u) => (u ? list.add(u) : list), toList<T>()); values = <T = unknown>(): List<T> => values<T>(this.subject); property = (property: string | symbol): PropertyMeta => new PropertyMeta(this.subject, property); } class PropertyMeta { constructor( readonly subject: any, readonly property: string | symbol, private readonly data = Reflect.getMetadata(property, subject) ) {} get value(): any { return this.subject[this.property]; } get = <T>(key: string): Optional<T> => (isDefined(this.data) && isDefined(this.data[key]) ? (this.data[key] as T) : undefined); set = <T>(key: string, value: T): T => { Reflect.defineMetadata(this.property, { ...this.data, [key]: value }, this.subject); return value; }; } export const meta = (subject: unknown): ClassMeta => new ClassMeta(subject ?? {});