Source: members/pullmember.js

/**
 * @file Dynasty, asynchronous dependency injection.
 * @author Adam Mill <hismajesty@theroyalwhee.com>
 * @copyright Copyright 2019-2021 Adam Mill
 * @license Apache-2.0
 */

/**
 * Imports.
 */
const { isObject, isArray, isFunction } = require('@theroyalwhee0/istype');

/**
 * Pull Member Function factory.
 * @returns {Function} The pullMember function.
 */
function pullMemberFactory() {
  /**
   * Get a member property from an attached dependency and use it as this item.
   * This is a builder function.
   * @public
   * @typedef pullMember
   * @function
   * @param {string} name The attached dependency to pull from.
   * @param {string} member The member property name to pull.
   * @param {object} options Options.
   * @param {boolean} options.bind If the property is a function bind to parent. Defaults to true.
   * @returns {promise<function>} The resulting parameter function.
   */
  return function pullMember(name, member, { bind = true } = {}) {
    function pullMemberParam(item) {
      item.creator = (dyn) => {
        const attached = dyn();
        if(!(name in attached)) {
          return Promise.reject(new Error(`node "${name}" not attached`));
        }
        const item = attached[name];
        if(!(isObject(item) || isArray(item) || isFunction(item))) {
          return Promise.reject(new Error(`node "${name}" can not have members`));
        }
        if(!(member in item)) {
          return Promise.reject(new Error(`node "${name}" does not have a member "${member}"`));
        }
        const property = item[member];
        let results;
        if(bind && isFunction(property)) {
          // If it is a function then bind it.
          results = property.bind(item);
        } else {
          results = property;
        }
        return Promise.resolve(results);
      };
      return Promise.resolve(item);
    };
    return Promise.resolve(pullMemberParam);
  };
}

/**
 * Exports.
 */
module.exports = { pullMemberFactory };