UNPKG

envalid

Version:

Validation for your environment variables

94 lines (77 loc) 3.35 kB
const dotenv = require('dotenv') const { EnvError, EnvMissingError, makeValidator, bool, num, str, json, url, email } = require('./lib/validators') const defaultReporter = require('./lib/reporter') const extend = (x = {}, y = {}) => Object.assign({}, x, y) /** * Validate a single env var, given a spec object * * @throws EnvError - If validation is unsuccessful * @return - The cleaned value */ function validateVar({ spec = {}, name, rawValue }) { if (typeof spec._parse !== 'function') { throw new EnvError(`Invalid spec for "${name}"`) } const value = spec._parse(rawValue) if (spec.choices) { if (!Array.isArray(spec.choices)) { throw new Error(`"choices" must be an array (in spec for "${name}")`) } else if (!spec.choices.includes(value)) { throw new EnvError(`Value "${value}" not in choices [${spec.choices}]`) } } if (value == null) throw new EnvError(`Invalid value for env var "${name}"`) return value } function cleanEnv(inputEnv, specs = {}, options = {}) { let output = {} let defaultNodeEnv = '' const errors = {} const env = extend(dotenv.config({ silent: true }), inputEnv) const varKeys = Object.keys(specs) // If validation for NODE_ENV isn't specified, use the default validation: if (!varKeys.includes('NODE_ENV')) { defaultNodeEnv = validateVar({ name: 'NODE_ENV', spec: str({ choices: ['development', 'test', 'production'] }), rawValue: env.NODE_ENV || 'production' }) } for (const k of varKeys) { const spec = specs[k] const devDefault = (env.NODE_ENV === 'production' ? undefined : spec.devDefault) let rawValue = env[k] if (rawValue === undefined) { rawValue = (devDefault === undefined ? spec.default : devDefault) } // Default values can be anything falsy (besides undefined), without // triggering validation errors: const usingFalsyDefault = ((spec.default !== undefined) && (spec.default === rawValue)) || ((devDefault !== undefined) && (devDefault === rawValue)) try { if (rawValue === undefined && !usingFalsyDefault) throw new EnvMissingError(spec.desc || '') output[k] = validateVar({ name: k, spec, rawValue }) } catch (err) { if (options.reporter === null) throw err errors[k] = err } } // If we need to run Object.assign() on output, we must do it before the // defineProperties() call, otherwise the properties would be lost output = options.strict ? output : extend(env, output) Object.defineProperties(output, { isDev: { value: (defaultNodeEnv || output.NODE_ENV) === 'development' }, isProduction: { value: (defaultNodeEnv || output.NODE_ENV) === 'production' }, isTest: { value: (defaultNodeEnv || output.NODE_ENV) === 'test' } }) if (options.transformer) { output = options.transformer(output) } const reporter = options.reporter || defaultReporter reporter({ errors, env: output }) return Object.freeze(output) } module.exports = { cleanEnv, makeValidator, bool, num, str, json, url, email, EnvError, EnvMissingError }