UNPKG

@adonisjs/framework

Version:

Adonis framework makes it easy for you to write webapps with less code

216 lines (196 loc) 4.86 kB
'use strict' /** * adonis-framework * * (c) Harminder Virk <virk@adonisjs.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ const _ = require('lodash') const path = require('path') const dotenv = require('dotenv') const fs = require('fs') const GE = require('@adonisjs/generic-exceptions') const debug = require('debug')('adonis:framework') /** * Manages the application environment variables by * reading the `.env` file from the project root. * * If `.env` file is missing, an exception will be thrown * to supress the exception, pass `ENV_SILENT=true` when * starting the app. * * Can define different location by setting `ENV_PATH` * environment variable. * * @binding Adonis/Src/Env * @group Core * @alias Env * @singleton * * @class Env * @constructor */ class Env { constructor (appRoot) { this.appRoot = appRoot const bootedAsTesting = process.env.NODE_ENV === 'testing' const env = this.load(this.getEnvPath(), false) // do not overwrite at first place /** * Throwing the exception when ENV_SILENT is not set to true * and ofcourse there is an error */ if (env.error && process.env.ENV_SILENT !== 'true') { throw env.error } /** * Load the `.env.testing` file if app was booted * under testing mode */ if (bootedAsTesting) { this.load('.env.testing') } } /** * Replacing dynamic values inside .env file * * @method _interpolate * * @param {String} env * @param {Object} envConfig * * @return {String} * * @private */ _interpolate (env, envConfig) { const matches = env.match(/(\\)?\$([a-zA-Z0-9_]+)|(\\)?\${([a-zA-Z0-9_]+)}/g) || [] _.each(matches, (match) => { /** * Variable is escaped */ if (match.indexOf('\\') === 0) { env = env.replace(match, match.replace(/^\\\$/, '$')) return } const key = match.replace(/\$|{|}/g, '') const variable = envConfig[key] || process.env[key] || '' env = env.replace(match, this._interpolate(variable, envConfig)) }) return env } /** * Load env file from a given location. * * @method load * * @param {String} filePath * @param {Boolean} [overwrite = 'true'] * @param {String} [encoding = 'utf8'] * * @return {Object} */ load (filePath, overwrite = true, encoding = 'utf8') { const options = { path: path.isAbsolute(filePath) ? filePath : path.join(this.appRoot, filePath), encoding } try { const envConfig = dotenv.parse(fs.readFileSync(options.path, options.encoding)) /** * Dotenv doesn't overwrite existing env variables, so we * need to do it manaully by parsing the file. */ debug('%s environment file from %s', overwrite ? 'merging' : 'loading', options.path) /** * Loop over values and set them on environment only * when actual value is not defined or overwrite * is set to true */ _.each(envConfig, (value, key) => { if (process.env[key] === undefined || overwrite) { process.env[key] = this._interpolate(value, envConfig) } }) return { parsed: envConfig } } catch (error) { return { error } } } /** * Returns the path from where the `.env` * file should be loaded. * * @method getEnvPath * * @return {String} */ getEnvPath () { if (!process.env.ENV_PATH || process.env.ENV_PATH.length === 0) { return '.env' } return process.env.ENV_PATH } /** * Get value for a given key from the `process.env` * object. * * @method get * * @param {String} key * @param {Mixed} [defaultValue = null] * * @return {Mixed} * * @example * ```js * Env.get('CACHE_VIEWS', false) * ``` */ get (key, defaultValue = null) { return _.get(process.env, key, defaultValue) } /** * Get value for a given key from the `process.env` * object or throw an error if the key does not exist. * * @method getOrFail * * @param {String} key * * @return {Mixed} * * @example * ```js * Env.getOrFail('MAIL_PASSWORD') * ``` */ getOrFail (key) { const val = _.get(process.env, key) if (_.isUndefined(val)) { throw GE.RuntimeException.missingEnvKey(key) } return val } /** * Set value for a given key inside the `process.env` * object. If value exists, will be updated * * @method set * * @param {String} key * @param {Mixed} value * * @return {void} * * @example * ```js * Env.set('PORT', 3333) * ``` */ set (key, value) { _.set(process.env, key, value) } } module.exports = Env