UNPKG

moleculer-decorators

Version:
130 lines (107 loc) 4.29 kB
import { ServiceSchema, Action, ActionHandler, LoggerInstance, ServiceMethods, ServiceEvents, Actions, Context, ServiceSettingSchema, GenericObject } from 'moleculer'; import * as _ from 'lodash'; import Bluebird = require('bluebird'); const blacklist = ['created', 'started', 'stopped', 'actions', 'methods', 'events']; const blacklist2 = ['metadata', 'settings', 'mixins', 'name', 'version'].concat(blacklist); const defaultServiceOptions: Options = { constructOverride: true } export class BaseSchema { logger: LoggerInstance; name: string; version?: string | number; settings?: ServiceSettingSchema; metadata?: GenericObject; mixins?: Array<ServiceSchema>; actions?: Actions; methods?: ServiceMethods; events?: ServiceEvents; } export interface Options extends Partial<ServiceSchema> { name?: string constructOverride?: boolean } export interface ActionOptions extends Partial<Action> { name?: string, handler?: ActionHandler // Not really used } export function Method(target, key, descriptor) { (target.methods || (target.methods = {}))[key] = descriptor.value } export function Event(target, key, descriptor) { (target.events || (target.events = {}))[key] = descriptor.value } export function Action(options: ActionOptions = {}) { return function(target, key, descriptor) { (target.actions || (target.actions = {}))[key] = (options ? { ...options, handler: descriptor.value } : descriptor.value); } } export function Service(options: Options = {}) : any { return function(target) { let base = {} const _options = _.extend({}, defaultServiceOptions, options); Object.defineProperty(base, 'name', { value: options.name || target.name, writable: false, enumerable: true }); if (options.name) { delete options.name; // not needed } Object.assign(base, _.omit(options, _.keys(defaultServiceOptions))); // Apply const proto = target.prototype; const vars = []; Object.getOwnPropertyNames(proto).forEach(function (key) { if (key === 'constructor') { if (_options.constructOverride) { // Override properties defined in @Service const ServiceClass = new target.prototype[key]; Object.getOwnPropertyNames(ServiceClass).forEach(function(key) { if (blacklist.indexOf(key) === -1 && !_.isFunction(ServiceClass[key])) { base[key] = Object.getOwnPropertyDescriptor(ServiceClass, key)!.value if (blacklist2.indexOf(key) === -1) { // Needed, otherwize if the service is used as a mixin, these variables will overwrite the toplevel's vars[key] = Object.getOwnPropertyDescriptor(ServiceClass, key)!.value } } }); /* Insane hack below :D * It's needed since moleculer don't transfer all defined props in the * schema to the actual service, so we have to do it. */ const bypass: any = Object.defineProperty, // typescript fix obj: any = {}; // placeholder bypass(obj, 'created', { value: function created() { for (let key in vars) { this[key] = vars[key]; } if (!_.isNil(Object.getOwnPropertyDescriptor(proto, 'created'))) { Object.getOwnPropertyDescriptor(proto, 'created').value.call(this); } }, writable: true, enumerable: true, configurable: true }); base['created'] = obj.created; } return; } const descriptor = Object.getOwnPropertyDescriptor(proto, key)! if (key === 'created' && !_options.constructOverride) { base[key] = descriptor.value; } if (key === 'started' || key === 'stopped') { base[key] = descriptor.value; return; } if (key === 'events' || key === 'methods' || key === 'actions') { (base[key] ? Object.assign(base[key], descriptor.value) : base[key] = descriptor.value) return; } }); return base; } }