UNPKG

dotenv-manipulator

Version:

Load, add, update or remove variables from both your .env file and process.env at runtime

189 lines (188 loc) 6.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fs = require("fs"); const path = require("path"); /** * dotenv Manipulator : * - Load environment variables from a `.env` to `process.env` * - Add, update, or remove variables from both your `.env` file and `process.env` <b>at runtime</b> * @example * // require * const Manipulator = require('dotenv-manipulator').default * @example * // import * import Manipulator from 'dotenv-manipulator' */ class Manipulator { /** * Starts dotenv Manipulator * @param envPath Path to `.env`, default is `process.cwd()`. * @param throwable If set to `true` functions throw errors whenever there's an incorrect input. * @param encoding Specify file encoding, default is `utf8`. * @example * // basic setup * const Manipulator = require('dotenv-manipulator') * const dotenvM = new Manipulator() * @example * // complete setup * const Manipulator = require('dotenv-manipulator') * const dotenvM = new Manipulator('/path/to/project', false, 'utf-8') * @example * // undefined = default value * const Manipulator = require('dotenv-manipulator') * const dotenvM = new Manipulator(undefined, true, 'latin1') */ constructor(envPath = path.normalize(process.cwd()), throwable = false, encoding = 'utf-8') { this.encoding = 'utf-8'; this.encoding = encoding; this.throwable = throwable; this.env_path = path.join(envPath, '.env'); if (!fs.existsSync(this.env_path)) { fs.closeSync(fs.openSync(this.env_path, 'w')); } this.env = this.__readSync(); this.__sort(); } __readSync() { const OBJ = {}; const file = fs.readFileSync(this.env_path, { encoding: this.encoding }).toString().split(/\r?\n/); if (file.length) { for (const line of file) { if (line !== '') { const keyvalue = line.split('='); if (keyvalue.length === 2) { OBJ[keyvalue[0]] = keyvalue[1]; process.env[keyvalue[0]] = keyvalue[1]; } } } } return OBJ; } /** * Add object keys and values to `.env` file and `process.env` * @param obj Object to add to the environment * @param force If you try to add a key/value pair that is already in the environment : `add(obj, true)` would update said variables and `add(obj)` would just ignore your input * @example * const obj = { REMOTE: '95.81.123.228', PORT: 3000 } * dotenvM.add(obj) * @example * // without force argument * console.log(process.env.REMOTE_PORT) //=> '3000' * dotenvM.add({ REMOTE_PORT: '2000' }) * console.log(process.env.REMOTE_PORT) //=> '3000' * * // with force argument set to true * dotenvM.add({ REMOTE_PORT: '2000' }, true) * console.log(process.env.REMOTE_PORT) //=> '2000' * @example * // DEBUGGING #1 * dotenvM.throwable = false * * let debug = dotenvM.add(['wrong', 'type', 'of', 'data']) * let debug_1 = dotenvM.add({ GOOOD: 'type', OF: 'data' }) * console.log(debug.message) //=> [ADD_ERROR]: object must be [object Object] but received [object Array] * console.log(debug_1) //=> undefined * * // DEBUGGING #2 * dotenvM.throwable = true * * try { * dotenvM.add(['wrong', 'type', 'of', 'data']) * } catch(e) { * console.log(e.message) //=> [ADD_ERROR]: object must be [object Object] but received [object Array] * } */ add(obj, force = false) { if (Object.prototype.toString.call(obj) !== '[object Object]') { const errorMessage = new TypeError(`[ADD_ERROR]: object must be [object Object] but received ${Object.prototype.toString.call(obj)}`); if (this.throwable) { throw errorMessage; } else { return errorMessage; } } for (const res of Object.entries(obj)) { const key = res[0]; const val = res[1]; if (!this.env[key]) { this.env[key] = val; process.env[key] = val; } else if (force) { this.env[key] = val; process.env[key] = val; } } this.__save(); } /** * Remove variable from `.env` file and `process.env` * @param obj Key(s) you want to remove * @example * // #1 * dotenvM.remove('REMOTE') * dotenvM.remove('PORT') * * // #2 * dotenvM.remove( { REMOTE: 'value that dotenvM wont read', PORT: 'no.. really it doesnt care' } ) * * // #3 * dotenvM.remove(['REMOTE', 'PORT']) */ remove(obj) { if (typeof obj === 'string') { delete process.env[obj]; delete this.env[obj]; } else if (Object.prototype.toString.call(obj) === '[object Object]') { for (const key of Object.keys(obj)) { delete process.env[key]; delete this.env[key]; } } else if (Array.isArray(obj)) { for (const key of obj) { delete process.env[key]; delete this.env[key]; } } else { const errorMessage = new TypeError(`[REMOVE_ERROR]: expected [object Object] or [object Array] or [String] but received ${Object.prototype.toString.call(obj)}`); if (this.throwable) { throw errorMessage; } else { return errorMessage; } } this.__save(); } __sort() { const order = {}; for (const key of Object.keys(this.env).sort()) { order[key] = this.env[key]; } this.env = order; } __save() { this.__sort(); let string = ''; for (const key in this.env) { if (Object.prototype.hasOwnProperty.call(this.env, key)) { const val = this.env[key]; string += key + '=' + val + '\n'; } } if (string.length) { fs.writeFileSync(this.env_path, string, { encoding: this.encoding }); } else { if (Object.keys(this.env).length === 0) { fs.writeFileSync(this.env_path, string, { encoding: this.encoding }); } } } } exports.default = Manipulator;