UNPKG

chain-simple

Version:

Main purpose of this package is - provide simple way to build chain between any item methods

174 lines 7.26 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.chainProps = chainProps; exports.makeConstructorInstancePropertiesChainable = makeConstructorInstancePropertiesChainable; const sat_utils_1 = require("sat-utils"); const logger_1 = require("./logger"); logger_1.logger.setLogLevel(process.env.CHAIN_SIMPLE_LOG_LEVEL); function extendProxed(target, propName, receiver, config) { if ((0, sat_utils_1.isObject)(config) && (0, sat_utils_1.isFunction)(config.extendProxed) && (0, sat_utils_1.isUndefined)(Reflect.get(target, propName, receiver))) { try { const extension = config.extendProxed(propName); if ((0, sat_utils_1.isObject)(extension)) { Object.assign(target, extension); } else if ((0, sat_utils_1.isFunction)(extension)) { const result = extension(target); Object.assign(target, result); } } catch (error) { console.error(error); } return target; } } /** * @example * const {chainProps} = require('chain-simple'); * const obj = { * async method1() { * return Promise.resolve(1).then(value => { * console.log('method1', value); * return value; * }); * }, * async method2() { * return Promise.resolve(2).then(value => { * console.log('method2', value); * return value; * }); * }, * async method3() { * return Promise.resolve(3).then(value => { * console.log('method3', value); * return value; * }); * }, * }; * const chainableObj = chainProps(obj); * obj.method1().method3().then((val) => console.log(val)) * * * @param {!object} item * @param {{getEntity: string}} [config] config to describe how to get original not project object * @returns {object} object with chainable properties */ function chainProps(item, config) { const promiseCallableProps = ['then', 'catch', 'finally']; const propsList = []; if ((0, sat_utils_1.isObject)(config) && config.getEntityPropList) { if (!(0, sat_utils_1.isObject)(config.getEntityPropList) && !(0, sat_utils_1.isArray)(config.getEntityPropList)) { throw new TypeError('config "getEntityPropList" should be an array or an object'); } propsList.push(...((0, sat_utils_1.isObject)(config.getEntityPropList) ? Object.keys(config.getEntityPropList) : config.getEntityPropList)); } if (!(0, sat_utils_1.canBeProxed)(item)) { throw new TypeError('chainProps(): first argument should be an entity that can be proxed'); } if (!(0, sat_utils_1.isUndefined)(config) && !(0, sat_utils_1.isObject)(config)) { throw new TypeError('chainProps(): second argument should be an object'); } const _config = { ...config }; let proxifiedResult = item; const proxed = new Proxy(item, { get(_t, p, r) { if (propsList.length && propsList.includes(p)) { const propValue = Reflect.getOwnPropertyDescriptor(item, p)?.value; if ((0, sat_utils_1.isFunction)(propValue) || (0, sat_utils_1.isAsyncFunction)(propValue)) { return item[p].bind(item); } return item[p]; } if (_config.extendOnly) { extendProxed(item, p, r, config); return item[p]; } if (_config.getEntity === p) { return item; } if (p === Symbol.toStringTag) { return proxifiedResult[Symbol.toStringTag]; } if (p === 'toString') { return function (...args) { return proxifiedResult.toString(...args); }; } if (p === 'toJSON') { return function () { return proxifiedResult; }; } if (!promiseCallableProps.includes(p)) { extendProxed(item, p, r, config); } const isCallable = (0, sat_utils_1.isFunction)(Reflect.get(item, p, r)) || (0, sat_utils_1.isAsyncFunction)(Reflect.get(item, p, r)); if (!isCallable && !(0, sat_utils_1.isPromise)(proxifiedResult) && item[p] && !proxifiedResult[p]) { logger_1.logger.chainer(`[CHAIN_SIMPLE]: ${String(p)} is not a callable.`); return item[p]; } else if (isCallable) { logger_1.logger.chainer(`[CHAIN_SIMPLE]: ${String(p)} is a callable.`); return function (...arguments_) { logger_1.logger.chainer(`[CHAIN_SIMPLE]: ${String(p)} is called with args: `, ...arguments); if ((0, sat_utils_1.isPromise)(proxifiedResult)) { logger_1.logger.chainer(`[CHAIN_SIMPLE]: previous call result is a promise`); proxifiedResult = proxifiedResult.then(function (r) { logger_1.logger.chainer(`[CHAIN_SIMPLE]: previous call result is: `, r); return item[p].call(item, ...arguments_); }); } else { logger_1.logger.chainer(`[CHAIN_SIMPLE]: previous call result is not a promise`); logger_1.logger.chainer(`[CHAIN_SIMPLE]: previous call result is: `, proxifiedResult); proxifiedResult = item[p].call(item, ...arguments_); } return proxed; }; } else if (promiseCallableProps.includes(p) && (0, sat_utils_1.isPromise)(proxifiedResult)) { logger_1.logger.chainer(`[CHAIN_SIMPLE]: previous call result is a promise and next call is a promise method call`); if (!(0, sat_utils_1.isPromise)(proxifiedResult)) { return proxifiedResult; } return function (onRes, onRej) { const promised = proxifiedResult; proxifiedResult = item; return promised[p].call(promised, onRes, onRej); }; } else if (proxifiedResult[p]) { return proxifiedResult[p]; } if (!(p in item) && p in proxifiedResult) { return proxifiedResult[p]; } }, /** @info base */ getPrototypeOf(_t) { return Object.getPrototypeOf(proxifiedResult); }, ownKeys(_t) { return Object.getOwnPropertyNames(proxifiedResult); }, getOwnPropertyDescriptor(_t, p) { return Object.getOwnPropertyDescriptor(proxifiedResult, p); }, }); return proxed; } function handlerConstructor(config) { return { construct(target, args) { const item = new target(...args); return chainProps(item, config); }, }; } function makeConstructorInstancePropertiesChainable(constructorFunction, config) { return new Proxy(constructorFunction, handlerConstructor(config)); } //# sourceMappingURL=index.js.map