UNPKG

@feathersjs/hooks

Version:

Async middleware for JavaScript and TypeScript

196 lines (195 loc) 5.95 kB
import { copyProperties } from './utils.js'; export const HOOKS = Symbol.for('@feathersjs/hooks'); /** * The base hook context. */ export class BaseHookContext { constructor(data = {}) { Object.defineProperty(this, "self", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.assign(this, data); } toJSON() { const keys = Object.keys(this); let proto = Object.getPrototypeOf(this); while (proto) { keys.push(...Object.keys(proto)); proto = Object.getPrototypeOf(proto); } return keys.reduce((result, key) => { result[key] = this[key]; return result; }, {}); } } export class HookManager { constructor() { Object.defineProperty(this, "_parent", { enumerable: true, configurable: true, writable: true, value: null }); Object.defineProperty(this, "_params", { enumerable: true, configurable: true, writable: true, value: null }); Object.defineProperty(this, "_middleware", { enumerable: true, configurable: true, writable: true, value: null }); Object.defineProperty(this, "_props", { enumerable: true, configurable: true, writable: true, value: null }); Object.defineProperty(this, "_defaults", { enumerable: true, configurable: true, writable: true, value: void 0 }); } parent(parent) { this._parent = parent; return this; } middleware(middleware) { this._middleware = middleware?.length ? middleware : null; return this; } getMiddleware() { const previous = this._parent?.getMiddleware(); if (previous && this._middleware) { return previous.concat(this._middleware); } return previous || this._middleware; } collectMiddleware(self, _args) { const otherMiddleware = getMiddleware(self); const middleware = this.getMiddleware(); if (otherMiddleware && middleware) { return otherMiddleware.concat(middleware); } return otherMiddleware || middleware || []; } props(props) { if (!this._props) { this._props = {}; } copyProperties(this._props, props); return this; } getProps() { const previous = this._parent?.getProps(); if (previous && this._props) { return copyProperties({}, previous, this._props); } return previous || this._props || null; } params(...params) { this._params = params; return this; } getParams() { const previous = this._parent?.getParams(); if (previous && this._params) { return previous.concat(this._params); } return previous || this._params; } defaults(defaults) { this._defaults = defaults; return this; } getDefaults(self, args, context) { const defaults = typeof this._defaults === 'function' ? this._defaults(self, args, context) : null; const previous = this._parent?.getDefaults(self, args, context); if (previous && defaults) { return Object.assign({}, previous, defaults); } return previous || defaults; } getContextClass(Base = BaseHookContext) { const ContextClass = class ContextClass extends Base { constructor(data) { super(data); } }; const params = this.getParams(); const props = this.getProps(); if (params) { params.forEach((name, index) => { if (props?.[name] !== undefined) { throw new Error(`Hooks can not have a property and param named '${name}'. Use .defaults instead.`); } Object.defineProperty(ContextClass.prototype, name, { enumerable: true, get() { return this?.arguments[index]; }, set(value) { this.arguments[index] = value; } }); }); } if (props) { copyProperties(ContextClass.prototype, props); } return ContextClass; } initializeContext(self, args, context) { const ctx = this._parent ? this._parent.initializeContext(self, args, context) : context; const defaults = this.getDefaults(self, args, ctx); if (self) { ctx.self = self; } ctx.arguments = args; if (defaults) { for (const name of Object.keys(defaults)) { if (ctx[name] === undefined) { ctx[name] = defaults[name]; } } } return ctx; } } export function convertOptions(options = null) { if (!options) { return new HookManager(); } return Array.isArray(options) ? new HookManager().middleware(options) : options; } export function getManager(target) { return (target && target[HOOKS]) || null; } export function setManager(target, manager) { const parent = getManager(target); target[HOOKS] = manager.parent(parent); return target; } export function getMiddleware(target) { const manager = getManager(target); return manager ? manager.getMiddleware() : null; } export function setMiddleware(target, middleware) { const manager = new HookManager().middleware(middleware); return setManager(target, manager); }