import { IMessage } from './message'; /** * Message data object for staged handling * Response value is always mandatory. */ export interface IMessageData { text?: string; data?: any; compose?: any[]; value: any; } export type IMessageHandler = (data: IMessageData | string, reject: (error: Error) => void, next: IMessageHandler) => void; /** * Staged messaging handler */ export class MessageResolver { private handlers: IMessageHandler[] = []; public static textFormatter(text: string | undefined, value: any): string { let stri = text || ''; if (Array.isArray(value) || typeof value === 'object') { stri = stri.replace(/%([a-z]+)?(\d+)?/ig, (substr: string, word?: string, nr?: number): string => { if (nr && typeof nr === 'string') { nr = parseInt(nr as 'string', 10); } if (Array.isArray(value) && nr != null) { return value[nr]; } if (!word) { return substr; } const val = value[word]; if (Array.isArray(val) && nr) { return val[nr]; } return val; }); } else if (value === 'string') { if (!text) { stri = value; } else { text += ' ' + value; } } return stri; } constructor(public msg: IMessage) {} /** * Inject a middleware message handler * @param fn Message handler function */ use(fn: IMessageHandler): void { this.handlers.push(fn); } /** * Resolve the message. Call this only from the last plugin in the chain. * @param data Message response data */ resolve(data: IMessageData | string, ...rest: any[]): void { const ist = this.handlers.pop(); if (!this.handlers.length || !ist) { if (typeof data === 'string') { this.msg.resolve(data, ...rest); return; } if (data.compose && Array.isArray(data.compose)) { this.msg.resolve(data.compose); return; } this.msg.resolve(MessageResolver.textFormatter(data.text, data.value)); return; } ist.call(this, data, this.msg.reject, this.resolve); } /** * Reject the message. You can call this from anywhere. * @param error Error */ reject(error: Error): void { this.msg.reject(error); } }