Source: members/once.js

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

/**
 * Imports.
 */
const UNSET = require('../unset');
const { isFunction } = require('@theroyalwhee0/istype');

/**
 * Once Function factory.
 * @returns {Function} The once function.
 */
function onceFactory() {
  /**
   * Call a factory function once. Additional calls will return the original value.
   * This is a builder function.
   * @public
   * @typedef once
   * @function
   * @param {function} builder The factory function to call.
   * @returns {promise<function>} The resulting parameter function.
   */
  return async function once(builder) {
    if(!isFunction(builder)) {
      throw new Error(`"builder" should be a function: "${builder}" (${typeof builder})`);
    }
    return function onceParam(item) {
      let result = UNSET;
      item.creator = (dyn) => {
        if(result === UNSET) {
          const args = item.args || [ ];
          try {
            result = Promise.resolve(builder(...args, dyn));
          } catch(ex) {
            result = Promise.reject(ex);
          }
        }
        return result;
      };
      return item;
    };
  };
}

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