node/environmentUtils.js

const { providerCreator } = require('../shared/jimpleFns');
/**
 * @module node/environmentUtils
 */

/**
 * @typedef {import('../shared/jimpleFns').ProviderCreator<O>} ProviderCreator
 * @template O
 */

/**
 * @typedef {Object} EnvironmentUtilsProviderOptions
 * @property {string} serviceName  The name that will be used to register an instance of
 *                                 {@link EnvironmentUtils}. Its default value is
 *                                 `environmentUtils`.
 * @parent module:node/environmentUtils
 */

/**
 * A simple service to avoid calling `process.env` on multiples places of an app.
 *
 * @parent module:node/environmentUtils
 * @tutorial environmentUtils
 */
class EnvironmentUtils {
  constructor() {
    /**
     * The current `NODE_ENV`. If the variable is empty, the value will be `development`.
     *
     * @type {string}
     * @access protected
     * @ignore
     */
    this._env = this.get('NODE_ENV', 'development');
    /**
     * Whether or not the environment is production.
     *
     * @type {boolean}
     * @access protected
     * @ignore
     */
    this._production = this.env === 'production';
  }
  /**
   * Checks whether an environment variable exists or not.
   *
   * @param {string} name  The name of the variable.
   * @returns {boolean}
   */
  exists(name) {
    // eslint-disable-next-line no-process-env
    return typeof process.env[name] !== 'undefined';
  }
  /**
   * Gets the value of an environment variable.
   *
   * @param {string}  name               The name of the variable.
   * @param {string}  [defaultValue='']  A fallback value in case the variable is
   *                                     `undefined`.
   * @param {boolean} [required=false]   If the variable is required and `undefined`, it
   *                                     will throw an error.
   * @returns {string}
   * @throws {Error} If `required` is set to `true` and the variable is `undefined`.
   */
  get(name, defaultValue = '', required = false) {
    let value;
    if (this.exists(name)) {
      // eslint-disable-next-line no-process-env
      value = process.env[name];
    } else {
      if (required) {
        throw new Error(`The following environment variable is missing: ${name}`);
      }

      value = defaultValue;
    }

    return value;
  }
  /**
   * Sets the value of an environment variable.
   *
   * @param {string} name               The name of the variable.
   * @param {string} value              The value of the variable.
   * @param {string} [overwrite=false]  If the variable already exists, the method won't
   *                                    overwrite it, unless you set this parameter to
   *                                    `true`.
   * @returns {boolean} Whether or not the variable was set.
   */
  set(name, value, overwrite = false) {
    let result;
    if (!this.exists(name) || overwrite) {
      // eslint-disable-next-line no-process-env
      process.env[name] = value;
      result = true;
    } else {
      result = false;
    }

    return result;
  }
  /**
   * Whether or not the environment is for development.
   *
   * @type {boolean}
   */
  get development() {
    return !this._production;
  }
  /**
   * The current `NODE_ENV`. If the variable is empty, the value will be `development`.
   *
   * @type {string}
   * @access protected
   * @ignore
   */
  get env() {
    return this._env;
  }
  /**
   * Whether or not the environment is production.
   *
   * @type {boolean}
   * @access protected
   * @ignore
   */
  get production() {
    return this._production;
  }
}
/**
 * The service provider to register an instance of {@link EnvironmentUtils} on the
 * container.
 *
 * @type {ProviderCreator<EnvironmentUtilsProviderOptions>}
 * @tutorial environmentUtils
 */
const environmentUtils = providerCreator((options = {}) => (app) => {
  app.set(options.serviceName || 'environmentUtils', () => new EnvironmentUtils());
});

module.exports.EnvironmentUtils = EnvironmentUtils;
module.exports.environmentUtils = environmentUtils;